Placer une classe .dontCloseDropdown
sur chaque élément cliquable présent dans le Dropdown qui ne doit pas refermer ce dernier.
1 2 3 |
$('.dontCloseDropdown').on('click', function(e) { e.stopPropagation(); }); |
Le bloc-notes professionnel d'un développeur front-end senior
Placer une classe .dontCloseDropdown
sur chaque élément cliquable présent dans le Dropdown qui ne doit pas refermer ce dernier.
1 2 3 |
$('.dontCloseDropdown').on('click', function(e) { e.stopPropagation(); }); |
Sous IE (Internet Explorer), j’ai un menu déroulant dropdown dont la partie déroulée (les sous-niveaux) se masque involontairement lorsqu’elle est survolée au passage de la souris.
Autrement dit, IE (même les versions les plus récentes) n’est pas capable de détecter une bordure CSS comme un élément « physique ». Dans le cas de mon menu, le sous-niveau est encadré par une bordure grise de 10px d’épaisseur. Lorsqu’on navigue à la souris et qu’on fait le chemin de l’entrée « Particuliers » vers le sous-menu correspondant (cf. capture ci-dessous), le curseur traverse la bordure ce qui a pour effet une perte de focus et une disparition prématurée de la partie déroulée. (La bordure incriminée est en noir dans ma capture – lorsque le curseur de la souris passe dessus, le sous-menu disparaît).
Ne pas utiliser la propriété CSS border
pour un habillage se trouvant sur le passage de la souris. 🙂
J’ai d’abord tenté (sans succès) de remplacer la border-top
par une ombre interne avec la propriété CSS box-shadow
et la valeur inset
.
La solution qui fonctionne consiste à utiliser un dégradé CSS (gradient
). On commence par générer son dégradé via un outil en ligne comme Ultimate CSS Gradient Generator par Colorzilla.
Le code CSS généré est le suivant:
1 2 3 4 5 6 |
/* Permalink - use to edit and share this gradient: http://colorzilla.com/gradient-editor/#000000+0,000000+10,ffffff+10,ffffff+100 */ background: #000000; /* Old browsers */ background: -moz-linear-gradient(top, #000000 0%, #000000 10%, #ffffff 10%, #ffffff 100%); /* FF3.6-15 */ background: -webkit-linear-gradient(top, #000000 0%,#000000 10%,#ffffff 10%,#ffffff 100%); /* Chrome10-25,Safari5.1-6 */ background: linear-gradient(to bottom, #000000 0%,#000000 10%,#ffffff 10%,#ffffff 100%); /* W3C, IE10+, FF16+, Chrome26+, Opera12+, Safari7+ */ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#000000', endColorstr='#ffffff',GradientType=0 ); /* IE6-9 */ |
Suivant les navigateurs qu’on souhaite supporter, on peut réduire le code à cette ligne (à condition d’utiliser un outil d’auto-prefixage CSS qui rajoute les -moz, -webkit, -o, -ms
en fonction du scope de navigateurs et OS prédéfinis) :
1 |
background: linear-gradient(to bottom, #000000 0%,#000000 10%,#ffffff 10%,#ffffff 100%); /* W3C, IE10+, FF16+, Chrome26+, Opera12+, Safari7+ */ |
Il reste ensuite à modifier cette ligne en fonction de notre besoin. Dans mon cas, remplacer par les bonnes couleurs et remplacer l’unité %
par du px
pour coller aux 10px
de ma bordure:
1 |
background: linear-gradient(to bottom, #000000 0%,#000000 10px,#ffffff 10px,#ffffff 100%); |
Problème: les composants Dropdown de Bootstrap et Foundation ne s’activent pas sur iPad et iPhone alors qu’ils fonctionnent sur n’importe quel périphérique sous Android.
Solution: il s’agit juste d’un problème de markup. Il faut obligatoirement utiliser l’élément <button type="button">Mon dropdown qui fonctionne sur les mobiles d'Apple</button>
et surtout pas l’élément <a>
(même avec un attribut role="button"
.
Moralité: Apple, c’est de la grosse daubasse.
1 2 3 4 5 6 7 8 9 10 11 12 |
<div class="TriProduct"> <span class="Filters-facets__title js-filter-title">Trier par</span> <ul class="Filters-facets__list"> <li> <a class="nameFilter" href="">Prix</a> </li> <li> <a class="nameFilter selected>Nouveautés</a> </li> </ul> <i class="icon icon-chevron-down"></i> </div> |
1 2 3 4 5 6 |
$('.TriProduct ul.Filters-facets__list').after('<i class="icon icon-chevron-down" />'); $('.TriProduct ul.Filters-facets__list + i.icon').on('click', function(){ $('.TriProduct ul.Filters-facets__list a.nameFilter').each(function(){ $(this).toggleClass('is-shown'); }); }); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
.TriProduct{ position: relative; .Filters-facets__title, .Filters-facets__list{ display: inline-block; } .Filters-facets__title{ font-family: $corporate-font-bold; &:after{ content: ":"; display: inline-block; margin: 0 8px; } } .Filters-facets__list{ vertical-align: top; min-width: 90px; border-bottom: 1px solid #000; position: absolute; .nameFilter{ position: absolute; display: block; background-color: #fff; padding: 0 2px; left: -99999em; text-decoration: none; color: $site-font-color; &.selected, &.is-shown{ position: relative; left: 0; } &.selected{ // text-decoration: underline; } } + .icon{ font-size: .6rem; padding-left: 6px; position: relative; left: 100%; &:hover{ cursor: pointer; } &:before{ position: relative; top: -3px; } } } } |
Source Keep multiple collapse open (with button to toggle) – Bootstrap 3.
L’astuce consiste à :
<div>
avec un id="accordion"
.data-parent="#accordion"
(dont la valeur fera référence à celle de l’id de la div englobante) et href="#collapseOne"
(dont la valeur sera unique pour chaque lien).id="collapseOne"
unique (dont la valeur fera référence à la valeur de l’attribut href placé sur le lien juste au-dessus).…et à ajouter un bout de code javaScript supplémentaire (voir plus bas).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
<div class="accordion" id="accordion"> <!--Article 1--> <div class="accordion-group"> <div class="accordion-heading"> <a class="accordion-toggle" data-toggle="collapse" data-parent="#accordion" href="#collapseOne"> Collapsible Group Item #1 </a> </div> <div id="collapseOne" class="accordion-body collapse"> <div class="accordion-inner"> Anim pariatur cliche reprehenderit, enim eiusmod high life accusamus terry richardson ad squid. 3 wolf moon officia aute, non cupidatat skateboard dolor brunch. Food truck quinoa nesciunt laborum eiusmod. Brunch 3 wolf moon tempor, sunt aliqua put a bird on it squid single-origin coffee nulla assumenda shoreditch et. Nihil anim keffiyeh helvetica, craft beer labore wes anderson cred nesciunt sapiente ea proident. Ad vegan excepteur butcher vice lomo. Leggings occaecat craft beer farm-to-table, raw denim aesthetic synth nesciunt you probably haven't heard of them accusamus labore sustainable VHS. </div> </div> </div> <!--Article 2--> <div class="accordion-group"> <div class="accordion-heading"> <a class="accordion-toggle" data-toggle="collapse" data-parent="#accordion" href="#collapseTwo"> Collapsible Group Item #2 </a> </div> <div id="collapseTwo" class="accordion-body collapse"> <div class="accordion-inner"> Anim pariatur cliche reprehenderit, enim eiusmod high life accusamus terry richardson ad squid. 3 wolf moon officia aute, non cupidatat skateboard dolor brunch. Food truck quinoa nesciunt laborum eiusmod. Brunch 3 wolf moon tempor, sunt aliqua put a bird on it squid single-origin coffee nulla assumenda shoreditch et. Nihil anim keffiyeh helvetica, craft beer labore wes anderson cred nesciunt sapiente ea proident. Ad vegan excepteur butcher vice lomo. Leggings occaecat craft beer farm-to-table, raw denim aesthetic synth nesciunt you probably haven't heard of them accusamus labore sustainable VHS. </div> </div> </div> <!--Article 3--> <div class="accordion-group"> <div class="accordion-heading"> <a class="accordion-toggle" data-toggle="collapse" data-parent="#accordion" href="#collapseThree"> Collapsible Group Item #3 </a> </div> <div id="collapseThree" class="accordion-body collapse"> <div class="accordion-inner"> Anim pariatur cliche reprehenderit, enim eiusmod high life accusamus terry richardson ad squid. 3 wolf moon officia aute, non cupidatat skateboard dolor brunch. Food truck quinoa nesciunt laborum eiusmod. Brunch 3 wolf moon tempor, sunt aliqua put a bird on it squid single-origin coffee nulla assumenda shoreditch et. Nihil anim keffiyeh helvetica, craft beer labore wes anderson cred nesciunt sapiente ea proident. Ad vegan excepteur butcher vice lomo. Leggings occaecat craft beer farm-to-table, raw denim aesthetic synth nesciunt you probably haven't heard of them accusamus labore sustainable VHS. </div> </div> </div> </div> |
1 2 3 4 5 6 7 8 9 10 11 |
$('a[data-toggle="collapse"]').on('click',function(){ var id=$(this).attr('href'); if($(id).hasClass('in')) { $(id).collapse('hide'); } else{ $(id).collapse('show'); } }); |
TODO : gérer les limites droite/gauche de la page.
Markup HTML :
1 2 3 4 5 6 7 8 9 |
<li class="js-facet"> <div class=""> <a aria-expanded="false" aria-haspopup="true" role="button" data-toggle="dropdown" class="btn-facet"> Shop by Prix<span class="caret"></span> </a> <div class="js-facet-values"> </div> </div> </li> |
Code jQuery :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
var facetValuesElement = $('.js-facetnav-refinements .js-facet'); // DO: Partie déroulée du dropdown centrée horizontalement par rapport à la largeur du libellé de premier niveau du menu var nav_sub_item_width = 370; facetValuesElement.each(function() { var nav_primary_item_width = $(this).outerWidth(); var wanted_value = (nav_sub_item_width / 2) - (nav_primary_item_width / 2); $(this).find('.js-facet-values').css({ 'width': nav_sub_item_width+'px', 'margin-left': -wanted_value }); }); // UNDO: Partie déroulée du dropdown centrée horizontalement par rapport à la largeur du libellé de premier niveau du menu facetValuesElement.each(function() { $(this).attr('style', ''); }); |
Il peut arriver qu’une charte prévoit un menu géant horizontal qui soit aligné sur les limites droite de la page et déroulant (dropdown menu Bootstrap).
1 2 3 4 5 6 7 8 9 |
.right-stack { position: relative; .navbar, .nav > li, .nav > li > a { position: static; } } |
Attention : la classe .right-stack
n’existe pas dans Bootstrap. Elle se réfère à une <div>
qui englobe l’ensemble du menu horizontal. Sa présence est importante au bon fonctionnement de cette astuce.
Les Buttons dropdowns dans la doc officielle de Bootstrap : http://getbootstrap.com/components/#btn-dropdowns.
Structure HTML; notez bien les emplacements des classes .open
et .dropdown-toggle
:
1 2 3 4 5 6 7 8 9 |
<div class="input-group-btn open"> <button data-toggle="dropdown" class="btn btn-default dropdown-toggle" type="button" aria-expanded="true"> Choisir <span class="caret"></span> </button> <ul role="menu" class="dropdown-menu"> <li><a href="#">Par défaut</a></li> [...] </ul> </div> |
Le navigateur ne tient pas compte de mes surcharges CSS. Ce sont les styles standards de .btn-default
qui prennent le pas sur la ré-écriture.
Remarque : le code ci-dessous utilise le caractère &
comme alias de la classe .btn-default
. Il s’agit d’une version LESS des styles Bootstrap.
1 2 3 4 5 6 7 8 9 10 11 12 |
:hover, &:focus, &.focus, &:active, &.active, .open > .dropdown-toggle& { text-decoration: none !important; color: @color !important; background-color: @background !important; border-color: @border !important; box-shadow: none; } |
Le code CSS fourni avec Bootstrap est erroné : en regard du markup HTML énoncé plus haut, la classe .open
n’existe pas dans la chaîne .open > .dropdown-toggle&
(ou .open > .dropdown-toggle.btn-default
). Le chemin correct serait &.dropdown-toggle
.
1 2 3 4 5 6 7 8 9 10 11 12 |
&:hover, &:focus, &.focus, &:active, &.active, &.dropdown-toggle { text-decoration: none !important; color: @color !important; background-color: @background !important; border-color: @border !important; box-shadow: none; } |
Ce type de comportement peut-être utilisé dans le cadre d’une adaptation pour supports mobiles d’un site desktop.
Code standard de Bootstrap, comme vu dans la doc officielle. Le sous menu s’ouvre par-dessus le contenu. La partie .navbar-header
et la partie .collapse
sont solidaires (imbriquées dans la même <nav class="navbar" />
).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<nav class="navbar"> <div class="navbar-header"> <button class="navbar-toggle" type="button" data-toggle="collapse" data-target=".js-navbar-collapse"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a class="navbar-brand" href="#">Dropdown Menu</a> </div> <div class="collapse navbar-collapse js-navbar-collapse"> <ul class="nav navbar-nav"> <li>...</li> </ul> </div> </nav> |
Le sous menu pousse le contenu vers le bas. On désolidarise la partie .navbar-header
de la partie .collapse
.
Attention : l’attribut data-target=".js-navbar-collapse"
de <button class="navbar-toggle" />
doit avoir le même libellé que la classe sur le <div class="collapse" />
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
<nav class="navbar"> <div class="navbar-header"> <button class="navbar-toggle" type="button" data-toggle="collapse" data-target=".js-navbar-collapse"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a class="navbar-brand" href="#">Dropdown Menu</a> </div> </nav> <nav class="navbar"> <div class="collapse navbar-collapse js-navbar-collapse"> <ul class="nav navbar-nav"> <li>...</li> </ul> </div> </nav> |
Source : Resolve the conflict between Bootstrap 3 and PrototypeJS
.
Source : http://jsfiddle.net/dgervalle/hhBc6/.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
jQuery.noConflict(); if (Prototype.BrowserFeatures.ElementExtensions) { var disablePrototypeJS = function (method, pluginsToDisable) { var handler = function (event) { event.target[method] = undefined; setTimeout(function () { delete event.target[method]; }, 0); }; pluginsToDisable.each(function (plugin) { jQuery(window).on(method + '.bs.' + plugin, handler); }); }, pluginsToDisable = ['collapse', 'dropdown', 'modal', 'tooltip']; disablePrototypeJS('show', pluginsToDisable); disablePrototypeJS('hide', pluginsToDisable); } jQuery(document).ready(function ($) { $('.bs-example-tooltips').children().each(function () { $(this).tooltip(); }); }); |
Source : http://jsfiddle.net/dgervalle/e8Apv/.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
require.config({ baseUrl: '/', paths: { 'jquery': "//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min", 'bootstrap': "//netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min" }, shim: { 'bootstrap': ['jquery'] }, map: { '*': { 'jquery': 'jQueryNoConflict' }, 'jQueryNoConflict': { 'jquery': 'jquery' } } }); define('jQueryNoConflict', ['jquery'], function ($) { return $.noConflict(); }); if (Prototype.BrowserFeatures.ElementExtensions) { require(['jquery', 'bootstrap'], function ($) { // Fix incompatibilities between BootStrap and Prototype var disablePrototypeJS = function (method, pluginsToDisable) { var handler = function (event) { event.target[method] = undefined; setTimeout(function () { delete event.target[method]; }, 0); }; pluginsToDisable.each(function (plugin) { $(window).on(method + '.bs.' + plugin, handler); }); }, pluginsToDisable = ['collapse', 'dropdown', 'modal', 'tooltip']; disablePrototypeJS('show', pluginsToDisable); disablePrototypeJS('hide', pluginsToDisable); }); } require(['jquery', 'bootstrap'], function($) { $(document).ready(function () { $('.bs-example-tooltips').children().each(function () { $(this).tooltip(); }); }); }); |