diff options
| author | polo <ordipolo@gmx.fr> | 2025-11-13 20:19:48 +0100 |
|---|---|---|
| committer | polo <ordipolo@gmx.fr> | 2025-11-13 20:19:48 +0100 |
| commit | d52afe5cc37ce1e88772e7cb7a40b54bbbebda83 (patch) | |
| tree | ce7fbb8109794c5a9d3c88a88a7dfd8db28c2023 | |
| parent | 9e28a093480220d63960a4431c2decc354a7c7ca (diff) | |
| download | cms-d52afe5cc37ce1e88772e7cb7a40b54bbbebda83.tar.gz cms-d52afe5cc37ce1e88772e7cb7a40b54bbbebda83.tar.bz2 cms-d52afe5cc37ce1e88772e7cb7a40b54bbbebda83.zip | |
classe CSS drop-left pour ouvrir des sous-menus à gauche, normes de responsive design: 480, 768 et 1024px
| -rw-r--r-- | public/css/head.css | 23 | ||||
| -rw-r--r-- | public/css/nav.css | 85 | ||||
| -rw-r--r-- | public/js/main.js | 27 |
3 files changed, 87 insertions, 48 deletions
diff --git a/public/css/head.css b/public/css/head.css index 4df68ba..b5acfec 100644 --- a/public/css/head.css +++ b/public/css/head.css | |||
| @@ -47,7 +47,7 @@ header h2 | |||
| 47 | font-size: medium; /* défaut = x-large */ | 47 | font-size: medium; /* défaut = x-large */ |
| 48 | margin: 10px; | 48 | margin: 10px; |
| 49 | } | 49 | } |
| 50 | @media screen and (max-width: 1000px){ | 50 | @media screen and (max-width: 1024px){ |
| 51 | header h1, header h2 | 51 | header h1, header h2 |
| 52 | { | 52 | { |
| 53 | margin: 8px; | 53 | margin: 8px; |
| @@ -119,8 +119,12 @@ header a | |||
| 119 | border-radius: 10px; | 119 | border-radius: 10px; |
| 120 | padding: 5px; | 120 | padding: 5px; |
| 121 | } | 121 | } |
| 122 | .header_content | ||
| 123 | { | ||
| 124 | padding: 20px 0; | ||
| 125 | } | ||
| 122 | 126 | ||
| 123 | @media screen and (max-width: 1000px){ | 127 | @media screen and (max-width: 1024px){ |
| 124 | .header_content | 128 | .header_content |
| 125 | { | 129 | { |
| 126 | padding: 15px 0; | 130 | padding: 15px 0; |
| @@ -130,20 +134,25 @@ header a | |||
| 130 | max-width: 160px; | 134 | max-width: 160px; |
| 131 | } | 135 | } |
| 132 | } | 136 | } |
| 133 | @media screen and (max-width: 800px){ | 137 | @media screen and (max-width: 768px){ |
| 134 | .header_content | 138 | .header_content |
| 135 | { | 139 | { |
| 136 | grid-template-columns: 2fr 1fr; /* on vire la colonne de gauche et on permet au deux autres de "se pousser" si besoin */ | 140 | /*grid-template-columns: 2fr 1fr;*/ /* on vire la colonne de gauche et on permet au deux autres de "se pousser" si besoin */ |
| 137 | padding: 10px; | 141 | /*padding: 10px;*/ |
| 142 | display: block; | ||
| 143 | max-width: 65%; | ||
| 144 | margin: auto; | ||
| 138 | } | 145 | } |
| 139 | .header_left_col | 146 | .header_left_col |
| 140 | { | 147 | { |
| 141 | display: none; | 148 | display: none; |
| 142 | } | 149 | } |
| 143 | } | 150 | } |
| 144 | @media screen and (max-width: 600px){ | 151 | @media screen and (max-width: 480px){ |
| 145 | .header_content | 152 | .header_content |
| 146 | { | 153 | { |
| 147 | display: block; | 154 | /*display: block;*/ |
| 155 | max-width: 100%; | ||
| 156 | padding: 10px; | ||
| 148 | } | 157 | } |
| 149 | } \ No newline at end of file | 158 | } \ No newline at end of file |
diff --git a/public/css/nav.css b/public/css/nav.css index a9bddf2..4c276be 100644 --- a/public/css/nav.css +++ b/public/css/nav.css | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | /*-- menu principal --*/ | 1 | /*-- menu principal --*/ |
| 2 | 2 | ||
| 3 | /* version horizontale */ | 3 | /* version horizontale */ |
| 4 | @media screen and (min-width: 601px){ | 4 | @media screen and (min-width: 769px){ |
| 5 | .nav_button{ | 5 | .nav_button{ |
| 6 | display: none; | 6 | display: none; |
| 7 | } | 7 | } |
| @@ -32,21 +32,28 @@ | |||
| 32 | border-top: 3px solid #13aff0; | 32 | border-top: 3px solid #13aff0; |
| 33 | } | 33 | } |
| 34 | /* élément du menu survolé, le positionnement relatif en fait la référence du positionnement suivant */ | 34 | /* élément du menu survolé, le positionnement relatif en fait la référence du positionnement suivant */ |
| 35 | .drop-right .sub-menu | 35 | .drop-right .sub-menu, .drop-left .sub-menu |
| 36 | { | 36 | { |
| 37 | position: absolute; /* positionnement par rapport au précédent "position" en CSS */ | 37 | position: absolute; /* positionnement par rapport au précédent "position" en CSS */ |
| 38 | left: 100%; | ||
| 39 | top: -3px; /* la bordure bleue fait 3px */ | 38 | top: -3px; /* la bordure bleue fait 3px */ |
| 40 | } | 39 | } |
| 40 | .drop-right .sub-menu{ | ||
| 41 | left: 100%; | ||
| 42 | } | ||
| 43 | .drop-left .sub-menu{ | ||
| 44 | right: 100%; | ||
| 45 | } | ||
| 41 | /* 1er sous-menu, poitionnement pour ne pas aggrandir l'élément parent */ | 46 | /* 1er sous-menu, poitionnement pour ne pas aggrandir l'élément parent */ |
| 42 | nav > ul > li > ul | 47 | nav > ul > li > ul{ |
| 43 | { | ||
| 44 | position: absolute; /* retire du flux, positionnement par rapport à la fenêtre */ | 48 | position: absolute; /* retire du flux, positionnement par rapport à la fenêtre */ |
| 45 | margin-top: 5px; | 49 | margin-top: 5px; |
| 46 | margin-left: -5px; | 50 | margin-left: -5px; |
| 47 | } | 51 | } |
| 52 | nav > ul > li > ul:has(.drop-left){ | ||
| 53 | right: 0; | ||
| 54 | } | ||
| 48 | 55 | ||
| 49 | @media screen and (max-width: 1000px){ /* entre 601 et 1000 */ | 56 | @media screen and (max-width: 1024px){ /* entre 769 et 1024 */ |
| 50 | .nav_main p | 57 | .nav_main p |
| 51 | { | 58 | { |
| 52 | font-size: 90%; | 59 | font-size: 90%; |
| @@ -54,33 +61,31 @@ | |||
| 54 | } | 61 | } |
| 55 | 62 | ||
| 56 | @media (pointer: fine){ | 63 | @media (pointer: fine){ |
| 57 | .nav_main > ul > li:hover | 64 | .nav_main > ul > li:hover{ |
| 58 | { | ||
| 59 | background-color: white; | 65 | background-color: white; |
| 60 | } | 66 | } |
| 61 | .drop-right > a > p:after{ | 67 | .drop-right > a > p:after{ |
| 62 | content: " ▶"; | 68 | content: " ▶"; |
| 63 | } | 69 | } |
| 70 | .drop-left > a > p:before{ | ||
| 71 | content: "◀ "; | ||
| 72 | } | ||
| 64 | } | 73 | } |
| 65 | } | 74 | } |
| 66 | @media screen and (max-width: 450px){ | 75 | @media screen and (max-width: 480px){ |
| 67 | .sub-menu p{ | 76 | .sub-menu p{ |
| 68 | font-size: 90%; | 77 | font-size: 90%; |
| 69 | } | 78 | } |
| 70 | } | 79 | } |
| 71 | 80 | ||
| 72 | @media screen and (min-width: 1000px){ | 81 | @media screen and (min-width: 1025px){ |
| 73 | nav > ul > li > ul{ | ||
| 74 | margin-left: -7px; /* annuler le déplacement dû au padding: 7px; dans ".nav_main li" */ | ||
| 75 | margin-top: 7px; | ||
| 76 | } | ||
| 77 | .nav_main li{ | 82 | .nav_main li{ |
| 78 | padding: 7px; | 83 | padding: 7px; |
| 79 | } | 84 | } |
| 80 | } | 85 | } |
| 81 | 86 | ||
| 82 | /* version petits écrans */ | 87 | /* version petits écrans */ |
| 83 | @media screen and (max-width: 600px){ | 88 | @media screen and (max-width: 768px){ |
| 84 | #nav_zone{ | 89 | #nav_zone{ |
| 85 | display: flex; | 90 | display: flex; |
| 86 | flex-direction: column; | 91 | flex-direction: column; |
| @@ -119,31 +124,40 @@ | |||
| 119 | padding-left: 25px; | 124 | padding-left: 25px; |
| 120 | padding-right: 5px; | 125 | padding-right: 5px; |
| 121 | } | 126 | } |
| 122 | |||
| 123 | /*nav > ul > li > ul{ | 127 | /*nav > ul > li > ul{ |
| 124 | margin-left: 0; | 128 | margin-left: 0; |
| 125 | }*/ | 129 | }*/ |
| 130 | |||
| 126 | @media (pointer: fine){ | 131 | @media (pointer: fine){ |
| 127 | .nav_main > ul > li:hover{ | 132 | .nav_main > ul > li:hover{ |
| 128 | background-color: yellow; | 133 | background-color: yellow; |
| 129 | } | 134 | } |
| 130 | .drop-right > a > p:after{ | 135 | .drop-right > a > p:after, .drop-left > a > p:after{ |
| 131 | content: ' ▼'; | 136 | content: ' ▼'; |
| 132 | } | 137 | } |
| 133 | } | 138 | } |
| 139 | |||
| 140 | @media (pointer: coarse){ | ||
| 141 | .drop-down.open, .drop-right.open, .drop-left.open{ | ||
| 142 | border-radius: 5px; | ||
| 143 | } | ||
| 144 | } | ||
| 134 | } | 145 | } |
| 135 | 146 | ||
| 136 | 147 | ||
| 137 | .nav_main | 148 | .nav_main{ |
| 138 | { | ||
| 139 | border: 2px solid #13aff0; | 149 | border: 2px solid #13aff0; |
| 140 | text-wrap: nowrap; | 150 | text-wrap: nowrap; |
| 141 | } | 151 | } |
| 142 | .sub-menu{ | 152 | .sub-menu{ |
| 143 | box-shadow: 1px 1px 3px black; | 153 | box-shadow: 1px 1px 3px black; |
| 144 | } | 154 | } |
| 155 | .sub-menu:has(.drop-left), .sub-menu:has(.drop-left) .sub-menu{ | ||
| 156 | box-shadow: -1px 1px 3px black; | ||
| 157 | } | ||
| 145 | ul{ | 158 | ul{ |
| 146 | margin: 0; | 159 | margin-top: 0; |
| 160 | margin-bottom: 0; | ||
| 147 | } | 161 | } |
| 148 | 162 | ||
| 149 | .nav_main p | 163 | .nav_main p |
| @@ -166,15 +180,15 @@ li:not(.current){ | |||
| 166 | background-color: initial; | 180 | background-color: initial; |
| 167 | font-weight: initial; | 181 | font-weight: initial; |
| 168 | } | 182 | } |
| 183 | .drop-down.open, .drop-down:hover{ | ||
| 184 | position: relative; /* permet d'aligner son enfant en position absolue à droite avec un right: 0; */ | ||
| 185 | } | ||
| 169 | 186 | ||
| 170 | 187 | ||
| 171 | /* sous-menus avec PC + souris | 188 | /* sous-menus avec PC + souris |
| 172 | mettre ici tous les blocs avec :hover, les navigateurs mobiles "simulent" les :hover, cassant le JS utilisé ici */ | 189 | mettre ici tous les blocs avec :hover, les navigateurs mobiles "simulent" les :hover, cassant le JS utilisé ici */ |
| 173 | @media (pointer: fine) /* fine => précision de la souris */ | 190 | @media (pointer: fine){ /* fine => précision de la souris */ |
| 174 | { | 191 | .drop-down:hover > .sub-menu, .drop-right:hover > .sub-menu, .drop-left:hover > .sub-menu{ |
| 175 | .drop-down:hover > .sub-menu, | ||
| 176 | .drop-right:hover > .sub-menu | ||
| 177 | { | ||
| 178 | display: block; | 192 | display: block; |
| 179 | } | 193 | } |
| 180 | .sub-menu li:hover /* écrase le fond blanc placé en même temps */ | 194 | .sub-menu li:hover /* écrase le fond blanc placé en même temps */ |
| @@ -187,7 +201,7 @@ mettre ici tous les blocs avec :hover, les navigateurs mobiles "simulent" les :h | |||
| 187 | content: ' ▼'; | 201 | content: ' ▼'; |
| 188 | font-size: x-small; | 202 | font-size: x-small; |
| 189 | } | 203 | } |
| 190 | .drop-right > a > p:after | 204 | .drop-right > a > p:after, .drop-left > a > p:before |
| 191 | { | 205 | { |
| 192 | font-size: x-small; | 206 | font-size: x-small; |
| 193 | } | 207 | } |
| @@ -203,22 +217,21 @@ mettre ici tous les blocs avec :hover, les navigateurs mobiles "simulent" les :h | |||
| 203 | font-size: x-small; | 217 | font-size: x-small; |
| 204 | vertical-align: text-bottom; | 218 | vertical-align: text-bottom; |
| 205 | } | 219 | } |
| 220 | .sub-menu{ | ||
| 221 | display: none; | ||
| 222 | background-color: white; | ||
| 223 | font-size: 95%; | ||
| 224 | } | ||
| 206 | 225 | ||
| 207 | /* écran tactile */ | 226 | /* écran tactile */ |
| 208 | @media (pointer: coarse) /* coarse = grossier = précision écran tactile */ | 227 | @media (pointer: coarse){ /* coarse = grossier = précision écran tactile */ |
| 209 | { | ||
| 210 | .sub-menu-toggle{ | 228 | .sub-menu-toggle{ |
| 211 | display: inline-block; /* visible sur écran tactile */ | 229 | display: inline-block; /* visible sur écran tactile */ |
| 212 | } | 230 | } |
| 213 | .drop-down.open > .sub-menu, .drop-right.open > .sub-menu{ | 231 | .drop-down.open > .sub-menu, .drop-right.open > .sub-menu, .drop-left.open > .sub-menu{ |
| 214 | display: block; | 232 | display: block; |
| 215 | } | 233 | } |
| 216 | .drop-down.open, .drop-right.open{ | 234 | .drop-down.open, .drop-right.open, .drop-left.open{ |
| 217 | background-color: yellow; | 235 | background-color: yellow; |
| 218 | } | 236 | } |
| 219 | } | 237 | } \ No newline at end of file |
| 220 | .sub-menu{ | ||
| 221 | display: none; | ||
| 222 | background-color: white; | ||
| 223 | font-size: 95%; | ||
| 224 | } | ||
diff --git a/public/js/main.js b/public/js/main.js index 7020971..c8e10b0 100644 --- a/public/js/main.js +++ b/public/js/main.js | |||
| @@ -59,6 +59,21 @@ function toggleTouchMenu(){ | |||
| 59 | } | 59 | } |
| 60 | } | 60 | } |
| 61 | 61 | ||
| 62 | function makeDropLeftMenuEntries(){ | ||
| 63 | // détection d'éléments de 1er niveau possédant un menu déroulant possédant un menu déroulant | ||
| 64 | document.getElementById('nav_zone').querySelector('.nav_main').querySelectorAll('.drop-down:has(.drop-right)').forEach(drop_down => { | ||
| 65 | const rect = drop_down.getBoundingClientRect(); // coordonnées spatiales | ||
| 66 | |||
| 67 | // il se situe dans la moitié droite | ||
| 68 | if((rect.width / 2 + rect.left) > (window.innerWidth / 2)){ // centre de l'élément > largeur de la fenêtre? | ||
| 69 | drop_down.querySelectorAll('.drop-right').forEach(drop_right => { | ||
| 70 | drop_right.classList.remove('drop-right'); | ||
| 71 | drop_right.classList.add('drop-left'); | ||
| 72 | }); | ||
| 73 | } | ||
| 74 | }); | ||
| 75 | } | ||
| 76 | |||
| 62 | // exécuté à la fin du chargement de la page | 77 | // exécuté à la fin du chargement de la page |
| 63 | document.addEventListener('DOMContentLoaded', () => { | 78 | document.addEventListener('DOMContentLoaded', () => { |
| 64 | 79 | ||
| @@ -70,17 +85,18 @@ document.addEventListener('DOMContentLoaded', () => { | |||
| 70 | 85 | ||
| 71 | // fermer les autres sous-menus de même niveau | 86 | // fermer les autres sous-menus de même niveau |
| 72 | // :scope pour pouvoir utiliser > pour restreindre aux frères directs | 87 | // :scope pour pouvoir utiliser > pour restreindre aux frères directs |
| 73 | li.parentElement.querySelectorAll(':scope > .drop-down, :scope > .drop-right').forEach(sibling => { | 88 | li.parentElement.querySelectorAll(':scope > .drop-down, :scope > .drop-right, :scope > .drop-left').forEach(sibling => { |
| 74 | if(sibling !== li){ | 89 | if(sibling !== li){ |
| 75 | sibling.classList.remove('open'); // fermer sous-menus frères | 90 | sibling.classList.remove('open'); // fermer sous-menus frères |
| 76 | sibling.querySelectorAll('.drop-right').forEach(desc => { | 91 | sibling.querySelectorAll('.drop-right, .drop-left').forEach(desc => { |
| 77 | desc.classList.remove('open'); // fermer sous-menus neveux | 92 | desc.classList.remove('open'); // fermer sous-menus neveux |
| 78 | }); | 93 | }); |
| 79 | } | 94 | } |
| 80 | }); | 95 | }); |
| 81 | 96 | ||
| 82 | if(!li.classList.toggle('open')){ // ouvrir ou fermer ce sous-menu | 97 | // ouvrir ou fermer un sous-menu |
| 83 | li.querySelectorAll('.drop-right').forEach(desc => { | 98 | if(!li.classList.toggle('open')){ |
| 99 | li.querySelectorAll('.drop-right, .drop-left').forEach(desc => { | ||
| 84 | desc.classList.remove('open'); // fermer sous-menus enfants | 100 | desc.classList.remove('open'); // fermer sous-menus enfants |
| 85 | }); | 101 | }); |
| 86 | } | 102 | } |
| @@ -88,6 +104,7 @@ document.addEventListener('DOMContentLoaded', () => { | |||
| 88 | }); | 104 | }); |
| 89 | 105 | ||
| 90 | navHeight(); // hauteur de <nav> en fonction de celle du menu en position fixe | 106 | navHeight(); // hauteur de <nav> en fonction de celle du menu en position fixe |
| 107 | makeDropLeftMenuEntries(); // changer en drop-left les drop-right des éléments du menu dans la moitié droite de la fenêtre | ||
| 91 | insertLocalDates(); | 108 | insertLocalDates(); |
| 92 | }); | 109 | }); |
| 93 | 110 | ||
| @@ -95,7 +112,7 @@ function navHeight(){ | |||
| 95 | const nav = document.querySelector('nav'); // détection | 112 | const nav = document.querySelector('nav'); // détection |
| 96 | const nav_zone = document.getElementById('nav_zone'); | 113 | const nav_zone = document.getElementById('nav_zone'); |
| 97 | const resize_observer = new ResizeObserver(entries => { // param de type tableau | 114 | const resize_observer = new ResizeObserver(entries => { // param de type tableau |
| 98 | let nav_button_height = window.innerWidth <= 600 ? 26 : 0; // 26 = taille du bouton | 115 | let nav_button_height = window.innerWidth <= 768 ? 26 : 0; // 26 = taille du bouton |
| 99 | nav_button_height += nav.classList.contains('show') ? 15 : 0; | 116 | nav_button_height += nav.classList.contains('show') ? 15 : 0; |
| 100 | for(const entry of entries){ | 117 | for(const entry of entries){ |
| 101 | nav_zone.style.height = (entry.contentRect.height + nav_button_height) + 'px'; | 118 | nav_zone.style.height = (entry.contentRect.height + nav_button_height) + 'px'; |
