Ответ 1
Меню с вкладками, которое вы используете, спроектировано так, что невозможно выбрать вкладку с JS.
Меню работает так, что все элементы обернуты внутри трех оболочек, один из которых нацелен, нажав на ссылку. Странам предоставляется стилизация, на основе которой был нацелен элемент-оболочка. Проблема в том, что вы не можете target
использовать элемент с помощью JS, поэтому вы не можете выбрать вкладку с помощью JS с вашим текущим кодом.
Но не беспокойтесь, это плохой способ делать вкладки только для CSS. Если вы это сделаете так, как показано в учебнике, о котором вы говорили, ни одна из вкладок не будет выбрана изначально до того, как пользователь нажмет на одну из вкладок. Кроме того, для этого требуется большая избыточная надбавка.
Я предлагаю вам вместо этого использовать radio buttons
(если вы хотите, чтобы навигация по меню вкладок работала исключительно с CSS, несмотря на то, что в любом случае использовала JS для некоторых других вещей). Преимущества использования radio buttons
:
- вы можете использовать JS для выбора вкладки с
element.checked=true;
- у вас может быть одна из вкладок, предварительно выбранных с помощью атрибута
checked
- гораздо меньше разметки, загромождающей ваш HTML
- еще чистое решение для CSS
Я уже создал функцию tab()
, которую вы можете использовать для выбора одной из вкладок. Например, tab(3)
будет выбирать третью вкладку.
Я попытался вдаваться в подробности, как мог, в комментариях к приведенному ниже коду. Но я понимаю, что для полноценного понимания требуется довольно хорошее знание селекторов CSS, поэтому спросите, не ясно ли что-то.
/*
With the following function you can select a tab to be displayed:
tab(1) selects the first tab for instance.
*/
function tab(number){
var elems=document.getElementsByTagName("input"), navs=[];
for(var i=0;i<elems.length;i++) if(elems[i].getAttribute("name")=="nav") navs.push(elems[i]);
navs[number-1].checked=true;
}
body {
overflow-x: hidden;
font-family: sans-serif;
text-align: center;
}
/*
You can select input elements whose name attribute is "nav" using
the [attribute=value] selector to select all our radio buttons
that'll become the tabs:
*/
input[name=nav]{
width: calc(100% / 3); /* third of the screen width */
height: 40px;
position: fixed;
top: 0;
left: 0;
margin: 0;
z-index: 2; /* this is so the ::before pseudo elements would be on top of the pages */
}
/*
To give separate styling for the second and the third tabs, you can use
the same selector again to target them specifically:
*/
input[value=i2]{
left:calc(100% / 3);
}
input[value=i3]{
left:calc(200% / 3);
}
/*
Radio buttons can't be styled, but the trick is to create an ::after
pseudo element and place it on top of the radio button. When the user
clicks on a pseudo element, it activates its parent selecting it. So,
in a nutshell, give the ::after pseudo element the styles you would for
the radio button.
*/
input[name=nav]::after{
content: attr(data-title); /* Display the value of the data-title attribute inside the element. */
display: block;
position: absolute;
top: 0; left: 0; /* Position it on top of its parent */
width: 100%; height: 100%; /* Make it the size as its parent */
padding: 5px;
background-color: #111;
cursor: pointer;
font: 2em/1 helvetica, arial;
font-weight: bold;
color: #aaa;
text-align: center;
box-sizing: border-box;
-webkit-transition: background 1s;
-moz-transition: background 1s;
transition: background 1s;
}
input[name=nav]:hover::after{ /* styling when hovering */
background-color: #444;
}
input[name=nav]:checked::after{ /* styling when the tab is selected */
background-color: red;
color: #fff;
}
/*
Now the ::after pseudo elements are enough for the tabs to work, but if
you want to have the back and forward buttons, you should create these
::before pseudo elements also. They work with the same idea. This time however,
their position is fixed so they can be placed on top of the pages.
Of course the back and forward buttons should only appear for tabs that
aren't currently selected, for which you can use the :not(:checked) selector:
*/
input[name=nav]:not(:checked)::before{
content: '';
display: block;
position: fixed;
top: 40px;
left: 0;
height: calc(100vh - 40px);
width: 50vw;
}
input[value=i1]:not(:checked)::before{
width:100vw;
}
input[value=i1]:checked ~ input[value=i3]::before{
left:0;
}
input[value=i1]:checked ~ input[value=i2]::before{
left:50vw;
}
input[value=i2]:checked ~ input[value=i3]::before{
left:50vw;
}
.pages{
position: fixed;
z-index:1;
top: 40px;
left: 0;
height: calc(100% - 40px);
width: 100%;
-webkit-transition: left 0.8s;
-moz-transition: left 0.8s;
transition: left 0.8s;
}
.page{
position: absolute;
top: 0;
width: 100%;
height: 100%;
}
.page#1 {
background-color: #bbb;
left: 0;
}
.page#i2 {
background-color: #ccc;
left: 100%;
}
.page#i3 {
background-color: #ddd;
left: 200%;
}
/*
Finally, use the "after" ~ selector to determine which page to show. The idea here is
that we first match which of the radio buttons are selected and then look for a .pages
element that follows it. This is the reason you shouldn't wrap the navigation elements
- they need to be on the same level in the DOM tree.
So, for instance if the first tab is selected, then input[value=i1]:checked is matched
and we can style the .pages element with the ~ selector because it comes after the
matched radio button in the DOM tree.
*/
input[value=i1]:checked ~ .pages {
left: 0%;
}
input[value=i2]:checked ~ .pages {
left: -100%;
}
input[value=i3]:checked ~ .pages {
left: -200%;
}
<!-- This is the navigation. It needs to be on the same level as
the pages in the DOM tree for the ~ selector to work, so don't
wrap it. Put the title you want displayed in the data-title
attribute. -->
<input type="radio" name="nav" value="i1" data-title="Tab 1" checked>
<input type="radio" name="nav" value="i2" data-title="Tab 2">
<input type="radio" name="nav" value="i3" data-title="Tab 3">
<!-- And here are your pages: -->
<div class="pages">
<div id="i1" class="page">
<h1>Slide 1</h1>
</div>
<div id="i2" class="page">
<h1>Slide 2</h1>
</div>
<div id="i3" class="page">
<h1>Slide 3</h1>
</div>
</div>