2016-07-15 1 views
3

J'essaie de créer un menu multi-niveaux avec une navigation de fil d'Ariane, sans utiliser javascript. J'ai rencontré des tas de menus et de chapelure purs de CSS, mais jamais combinés et travaillant ensemble. Voici une conception de ce que je suis en train de réaliser (cliquez sur le menu hamburger « plus »):Menu multi-niveaux css pur avec navigation fil d'Ariane fonctionnelle

https://invis.io/857RUKE6M

Et voici ce que j'ai jusqu'à présent dans mon html/css (voir le lien codepen ci-dessous) . S'il vous plaît pardonner le code brut/hacky. À ce stade, je ne fais que tester des idées, je vais simplifier et embellir mon code une fois que j'ai trouvé une solution.

http://codepen.io/jessbenz/pen/LZWjjz

Voici un extrait de code, mais s'il vous plaît regarder le lien codepen ci-dessus pour obtenir une meilleure idée:

<div class="smart-nav"> 
    <input type="radio" id="bread-home" class="breadcrumb" name="bread" /> 
    <input type="radio" id="bread-women" class="breadcrumb" name="bread" /> 
    <input type="radio" id="bread-womens-clothing" class="breadcrumb" name="bread" /> 
    <div class="smart-nav-panels"> 
     <ul id="home"> 

     <li> 
      <input type="radio" name="first"> 
      <label>1 Women</label> 
      <ul id="women"> 
      <li> 
       <input type="radio" name="second"> 
       <label>1.1 Women's Clothing</label> 
       <ul id="womens-clothing"> 
       <li> 
        <label>1.1.1 Women's Shirts</label> 
       </li> 
       </ul> 
      </li> 
      </ul> 
     </li> 

     <li> 
      <input type="radio" name="first"> 
      <label>2 Men</label> 
      <ul id="men"> 
      <li>2.1 Men's Shirts</li> 
      </ul>   
     </li> 

     </ul> 
    </div> 
</div> 

et mon SASS:

.breadcrumb:checked ~ .smart-nav-panels ul { 
    display: none; 
} 
#bread-home:checked ~ .smart-nav-panels > ul { 
    display: block; 
} 
#bread-women:checked ~ .smart-nav-panels { 
    #home, #women { 
    display: block; 
    } 
} 
#bread-womens-clothing:checked ~ .smart-nav-panels { 
    #home, #women, #womens-clothing { 
    display: block; 
    } 
} 
#bread-home:checked ~ .smart-nav-panels li input:checked > ul:first-child { 
    display: block; 
} 
.smart-nav-panels { 
    margin: 0; 
    padding: 0; 
    ul { 
    position: absolute; 
    top: 0; 
    left: 0; 
    right: 0; 
    bottom: 0; 
    width: 100%; 
    height: 100%; 
    background: lightgrey; 
    } 
    ul, li { 
    list-style: none; 
    margin: 0; 
    padding: 0; 
    } 
    > ul:first-child { 
    ul { 
     left: 100%; 
    } 
    } 
    li { 
    input + label + ul { 
     display: none; 
    } 
    input:checked + label + ul { 
     display: block; 
     // left:0; 
    } 
    } 
} 
input:checked ul { 
    display: block; 
} 

Si vous cliquez les vêtements des femmes dans mon échantillon de codepen, vous verrez que je suis à mi-chemin avec la réalisation de ce dont j'ai besoin. Les boutons radio horizontaux supérieurs représentent le fil d'Ariane et les boutons radio verticaux dans le bloc gris représentent le menu du niveau. Le problème vient quand je choisis une radio de fil d'Ariane. La diapositive correcte est affichée, mais si je sélectionne à nouveau une radio dans le menu, elle ne s'affiche pas car mon fil d'Ariane css prend la préférence et masque le contenu pertinent. Je suppose que c'est le problème de ne pas utiliser javascript. Comment faire en sorte que mes deux navigations soient conscientes les unes des autres avec un css pur? Il se pourrait que cette approche de combinaison de deux navigations radio soit incorrecte. J'espère vraiment que quelqu'un pourra partager sa sagesse. :)

Merci à l'avance

Répondre

1

Vous ne reculez devant un défi, pensez-vous? :)

Avant de me lancer dans d'autres détails, je dirais que la réponse courte est "construire un site statique". En d'autres termes, en supposant que l'une de vos contraintes de conception est "no javascript", déplacez le problème à un endroit où vous avez le luxe d'utiliser la logique de décision/code pour le rendre plus facile à résoudre (le serveur).

Même si vous parvenez à résoudre ce problème (et je ne suis pas sûr que ce soit possible compte tenu des contraintes de HTML/CSS), le prochain problème que vous allez avoir est d'attacher tout type de comportement à tout cela. Vous allez vouloir charger le contenu spécifique en fonction de la sélection du menu, et la seule façon que vous allez faire est avec:

  • un événement javascript ou
  • un lien statique (élément d'ancrage , d'où le «pourquoi» derrière ma réponse courte)

On pourrait charger tout le contenu et peut-être trouver un moyen de l'afficher conditionnellement, mais alors la question est "quelle est la profondeur du trou de lapin?". De plus, si vous construisez des téléphones à fonctionnalités et/ou des connexions lentes, le chargement de tout le contenu aura un impact négatif sur l'expérience de l'utilisateur. Après avoir dit tout cela, j'ai réussi à simplifier légèrement le CSS et à corriger un bug avec l'affichage des sous-catégories (voir les commentaires en ligne). Notez que seule la catégorie 'Femmes' se comporte comme prévu car il manque des styles pour 'Men' & 'Kids'.

.container { 
    position: relative; 
    width: 360px; 
    height: 480px; 
    border: 1px solid black; 
    margin: 20px auto 0 auto; 
} 

.breadcrumb { 
    margin-top: -20px; 
    display: inline-block; 
    vertical-align: top; 
} 

/* 
.breadcrumb:checked ~ .smart-nav-panels ul { 
    display: none; 
} 

#bread-home:checked ~ .smart-nav-panels > ul { 
    display: block; 
} 
*/ 

/* hide all uls except the 'home' ul by default, replaces both of the above */ 
.smart-nav-panels ul ul {  
    display: none; 
} 

/* 
#bread-women:checked ~ .smart-nav-panels { 
    #home, #women { 
    display: block; 
    } 
} 

#bread-womens-clothing:checked ~ .smart-nav-panels { 
    #home, #women, #womens-clothing { 
    display: block; 
    } 
} 
*/ 

/* these next 3 style definitions are very similar to what you had before (commented 
above), except that there is no longer a need to unhide the 'home' ul, and we're 
being more explicit about which uls to hide in correspondence with the state of the 
breadcrumb nav */ 
#bread-home:checked ~ .smart-nav-panels { 
    #women { 
    display: none; 
    } 
}  

#bread-women:checked ~ .smart-nav-panels { 
    #women { 
    display: block; 
    } 
    #womens-clothing, #womens-shoes { 
    display: none; 
    } 
} 

#bread-womens-clothing:checked ~ .smart-nav-panels { 
    #women, #womens-clothing { 
    display: block; 
    } 
} 

/* 
#bread-home:checked ~ .smart-nav-panels li input:checked > ul:first-child { 
    display: block; 
} 
*/ 

/* (i) the above didn't work because the ul isn't a direct descendant of the input, 
rather it is a sibling, and in addition it doesn't matter which breadcrumb item is 
checked now */ 
.smart-nav-panels li input:checked ~ ul { 
    display: block; 
} 

.smart-nav-panels { 
    margin: 0; 
    padding: 0; 
    ul { 
    position: absolute; 
    top: 0; 
    left: 0; 
    right: 0; 
    bottom: 0; 
    width: 100%; 
    height: 100%; 
    background: lightgrey; 
    } 
    ul, li { 
    list-style: none; 
    margin: 0; 
    padding: 0; 
    } 

    > ul:first-child { 
    ul { 
     left: 100%; 
    } 
    } 
    /* removed unnecessary styles here */ 
} 
/* removed unnecessary style here */ 

Cela a résolu certains des problèmes, mais il y en a encore beaucoup plus. Je suppose que résoudre certains d'entre eux en créera de nouveaux. Une chose que je peux penser immédiatement est que vous voudrez lier l'état du menu à plusieurs niveaux au fil d'Ariane de manière à ce que vous ne voyiez que la plus grande partie du fil d'Ariane que vous êtes supposé (en ce moment vous voyez toujours tout de celui-ci).

À un moment donné, vous allez vouloir événements (comportement) et les composants auront besoin de connaître l'autre de l'état . Alors que CSS a certaines capacités d'état il ne fournit rien sur le front de l'événement. Ces limitations, la nature en cascade (discutée en profondeur dans d'autres questions, par exemple: le manque de sélecteur ancêtre) et le couplage à la structure HTML contribuent tous à rendre ce problème très difficile à résoudre avec HTML seul.

Je comprends le désir d'avoir ce type de navigation sans JS et c'est certainement un problème intéressant à essayer et à résoudre, mais finalement je pense que c'est la mauvaise façon de s'y prendre. Il y a une raison pour laquelle javascript est si omniprésent - notre expérience du web tel qu'il est aujourd'hui ne serait tout simplement pas la même sans elle.

(Merci à Jess et d'autres collègues de la discussion qui a informé les parties de cette réponse. Je paraphrasé généreusement. Espérons que cela profite à quelqu'un d'autre.)

+0

Merci pour cette réponse complète et utile. Je dis utile parce que cela m'a découragé (pour l'instant) de passer beaucoup plus d'heures dans ce trou de lapin. Nous avons suspecté que cela ne pouvait pas se faire sans Javascript. Ce fut un défi amusant, et j'espère que le résultat sera utile aux autres. Merci également d'avoir amélioré mon CSS. :) –