28172 sujets

CSS et mise en forme, CSS3

Bonjour,

Je cale sur un point tout bête pour lequel je ne crois pas qu'il y ait de solutions full CSS, mais je tente quand-même de vous poser la question : est-il possible de répartir équitablement un nombre d'items indéterminés sur deux lignes ?

C'est pour le menu étendu de mon player que je souhaite améliorer :

upload/1685396661-35007-menu.jpg

Résultat attendu, les bouttons également répartis sur 2 lignes (au-delà de 6 boutons) :

upload/1685399357-35007-menu2.jpg

On peut le voir en action ici (les icônes avec les trois petits points) : Media players.

Le menu peut contenir de 5 à 8 boutons selon la nature du player et ses options, il est probable que j'en ajoute à l'avenir. Exemple de structure (simplifiée) :
<div class="media-extend-menu active">
  <button class="media-subtitles active"></button>
  <button class="media-slow-motion"></button>
  <button class="media-stop active"></button>
  <button class="media-replay"></button>
</div>

On est bien d'accord que c'est le conteneur (le menu ouvert avec la classe ".media-extend-menu") qui doit s'adapter aux nombres d'items (les boutons du menus), donc on ne s'en tire pas avec un max-width pour faire rentrer les boutons dans le rang...

En attendant j'ai trouvé une solution grid layout + JavaScript. Le JS contrôle la variable CSS "--mem" qui détermine le nombre de colonnes pour la grille :
menuButton.addEventListener('click', () => { // @note Fonction propre au player, non liée à la source mediaElement.
  menu(player, true)
  menuButton.classList.toggle('active')
  // @todo BEGIN test
  const extendMenu = player.querySelector('.media-extend-menu')
  const numberButtons = extendMenu.querySelectorAll('button').length
  let rows = numberButtons
  if (numberButtons > 6) rows = Math.ceil(numberButtons / 2) // Au delà d'un certain nombre, distribution des boutons sur 2 lignes de manière équitable.
  extendMenu.style.setProperty('--mem', rows)
  // @todo END test
})

Pour les tests isolés voici un CodePen.

Mais j'ai l'impression de sortir le bazooka pour un objectif uniquement esthétique. Il y a peut-être mieux, si vous avez des suggestions full CSS...
Modifié par Olivier C (30 May 2023 - 10:06)
Je ne comprends pas très bien ton problème, mais tu utilises des fonction "deprecate" et tu as une tonne d'erreurs (24 je crois).... désolé de ne pouvoir t'aider, mais corriges tes erreurs ça ira déjà mieux !
(clic droit sur ta page et choisi "inspecter"
Bon courage
Au cas ou essais ça

.media-extend-menu.active
  --mem: 7
  position: center
  bottom: auto
  right: 0
  
  //max-width: 18.5em
  align-content: end
  
  padding: .5em
  background-color: #222
  border-radius: 1.75em
  & button
    all: unset
    width: 2.5em
    height: 2.5em
    background-color: tomato
    border-radius: 50%

*
  box-sizing: border-box

body
  font-family: Arial
  color: #fff
  background-color: #333

.media-extend-menu
  text-align: center
  line-height: 2.5em


Modifié par Fox-infograp (29 May 2023 - 22:57)
Fox-infograp a écrit :
Je ne comprends pas très bien ton problème, mais tu utilises des fonction "deprecate" et tu as une tonne d'erreurs (24 je crois)

De quelles erreurs parle-t-on ?
Fox-infograp a écrit :
clic droit sur ta page et choisi "inspecter"

Effectivement... ça me rappelle vaguement quelque chose... Smiley hein

Pour le CSS, a priori ce n'est pas ça.
Merci pour les conseils.
Bonsoir,

Je pense peut-être à une bêtise
Mais totalement à l’arrache, parce que je n'ai pas bien compris le fonctionnement des préprocesseurs.
je suis passé en flex mais l'idée doit être la même en grid.

Pourquoi ne pas partir sur deux containers posés l'un au dessus de l’autre ?



.media-extend-menu.active1
  - for (let i = 0; i < 3; i++)
    button= i + 1
.media-extend-menu.active2
  - for (let i = 0; i < 4; i++)
    button= i + 1



.media-extend-menu.active1
  --mem: 6
  position: absolute
  bottom: 50px
  right: 0
  padding: .5em
  background-color: #222
  display: flex
  justify-content: space-between;
  border-radius: 20px 20px 0px 0px
  width: 200px
  & button
    all: unset
    width: 2.5em
    height: 2.5em
    background-color: tomato
    border-radius: 50%

.media-extend-menu.active2
  --mem: 6
  position: absolute
  bottom: 0
  right: 0
  display: flex
  justify-content: space-between
  width:200px
  padding: .5em
  background-color: #222
  border-radius: 0 0 20px 20px
  & button
    all: unset
    width: 2.5em
    height: 2.5em
    background-color: tomato
    border-radius: 50%

*
  box-sizing: border-box

body
  min-height: 100vh
  font-family: Arial
  color: #fff
  background-color: #333

.media-extend-menu
  text-align: center
  line-height: 2.5em



Modifié par uniuc (30 May 2023 - 01:53)
Bonjour,

Je l'ai aussi fait en flex : CodePen (et même en float pour les tests).

D'ailleurs le menu était originellement codé en flex avant d'être passé en grid.

Le truc c'est que l'on ne connaît pas le nombre de boutons à l'avance. Le fait de mettre les boutons dans deux conteneurs séparés ne résoudra donc pas le problème.
Modérateur
Ola,

voila mon cailloux à l'édifice : https://jsfiddle.net/3tpczmk8/1/

.wrapper {
  display: flex;
  flex-direction: column;
  flex-wrap: wrap;
  height:50px;
  width: fit-content;
  
}

.item {
  flex: 0 0 20px;
  width:20px;
  height:20px;
  background: pink;
  border-radius: 50%;
  text-align: center;
  line-height: 20px;
}


Bonne journée
@laurent : Ah oui, la distribution en colonne avec une hauteur max définie pour forcer à deux lignes max. J'y ai pensé mais ça oblige alors à une distribution verticale des items.
Modérateur
Bonjour,

Sans contrainte de dimensions sur le conteneur :
.media-extend-menu.active {
  position: absolute;
  bottom: 0;
  right: 0;
  display: grid;
  grid-gap: 0.5em;
  padding: 0.5em;
  background-color: #222;
  border-radius: 1.75em;
}
.media-extend-menu.active .item {
  width: 2.5em;
  height: 2.5em;
  background-color: #ff6347;
  border-radius: 50%;
}
* {
  box-sizing: border-box;
}
body {
  font-family: Arial;
  color: #fff;
  background-color: #333;
}
.media-extend-menu {
  text-align: center;
  line-height: 2.5em;
}
.media-extend-menu.active .item:nth-of-type(2n+1) {
	grid-row: 1;
}
.media-extend-menu.active .item:nth-of-type(2n) {
	grid-row: 2;
}
Certes, ça affiche toujours, comme avec la solution de _laurent les items pairs en dessous des items impairs au lieu de les afficher de gauche à droite.

Amicalement,
Ou plus simple une seule boite avec un max-width. Là il peut y avoir 17 boutons ou 52 sans problèmes. Sur button j'ai rajouté un margin-top.


.media-extend-menu.active
  --mem: 6
  position: absolute
  bottom: 0
  right: 0
  display: flex
  justify-content: space-between
  flex-wrap:wrap
  flex-direction: wrap
  flex-flow: wrap-reverse
  width:auto
  max-width:200px
  padding: .5em
  background-color: #222
  border-radius: 20px 20px 20px 20px
  & button
    all: unset
    width: 2.5em
    height: 2.5em
    margin-top: 7px
    background-color: tomato
    border-radius: 50%

Modifié par uniuc (30 May 2023 - 14:38)
Modérateur
Bonjour,
uniuc a écrit :
Ou plus simple une seule boite avec un max-width. Là il peut y avoir 17 boutons ou 52 sans problèmes.

Tu es sûr que y aura autant de boutons sur chaque ligne (tout en sachant qu'on ne sait pas combien il y a de boutons au départ) ?

J'ai quelques doutes ! Smiley cligne

Amicalement,
Modérateur
Bonjour,

Il y a dans un futur proche le sélecteur :has() qui pourrait servir à compter les enfants avec des sélecteurs redondants (préprocesseur bien utile du coup) , en gros on teste si une position est la dernière.

div:has(button:nth-child(4):last-child) 


exemple rapide : https://codepen.io/gc-nomade/pen/vYVwVOK

Firefox n'applique pas encore :has() mais on peut l'émuler pour voir comment il l’interprète actuellement. https://caniuse.com/css-has Bon c'est pas encore la solution non plus. Pour le moment, un javascript qui fait le comptage est la seule solution viable je dirais Smiley smile

Cdt
Meilleure solution
lol,

Non c'est certain on ne sais pas combien il y à de bouton... mais.

On sais déjà que de base il va y en avoir quatre ou plus, si je me base sur la photo on en est déjà à huit.

Je me dit que le nombre donc peut augmenter.

17 à 52 c'est excessif, c'est pour souligner qu'avec cette méthode il ne serras pas de limité, par rapport au nombre de boutons dont il va avoir besoin sur le lecteur.

L'idée dans ce que j'ai fait est surtout d'avoir des rangées de 4 bouton qui vont se placer les unes au dessus des autres, qu'il y ait 5 ou 8 boutons.
@uniuc le max-width est la solution de base que j'utilisais avant de faire le script. Comme je le disais dans mon premier message, je voulais éviter cette solution et passer à une répartition équitable des boutons pour que ça fasse plus propre.

@parsimonhi. Merci. Effectivement on reste en distribution verticale.

@gcyrillus. Bien vu, je n'avais pas pensé à :has(), c'est sans doute la solution pour l'avenir. C'est un sélecteur que j'utilise déjà par ailleurs avec mes grilles et que je profile déjà en JS pour Firefox. Remarque bien que la solution JS donnée au début fonctionne sans problème, mais je trouve agaçant de devoir surcharger mon code de base pour du code lié aux styles. Après je n'en mourrai pas.

D'un autre côté je peux aussi me dire "tant pis pour Firefox" à partir du moment où il lui reste une valeur de 6 boutons max par défaut et qu'il devrait prendre en charge cette fonctionnalité dans un avenir proche. Quoi qu'il en soit je pense que ta solution est top sur le plan CSS.

Édit : je m'attendais à ce que cette solution soit un peu verbeuse, mais au final pas tant que ça :
.media-extend-menu.active { /* code valable pour 5 boutons minimum */
  --mem: 6; /* nombre de colonnes par défaut */
  display: grid;
  grid-template-columns: repeat(var(--mem), 2.5em);
}
.media-extend-menu:has(button:nth-child(7):last-child, button:nth-child(8):last-child) {
  --mem: 4;
}
.media-extend-menu:has(button:nth-child(5):last-child, button:nth-child(9):last-child, button:nth-child(10):last-child) {
  --mem: 5;
}

Je pense que je vais l'adopter, sachant que les navigateurs ne prenant pas en charge :has() s'arrêterons toujours à 6 boutons max.

On peut aussi utiliser le JS comme solution de repli, avec un try/catch pour éviter de faire double emploi avec le CSS :
try { // Solution de repli pour ".media-extend-menu" si règle CSS :has() non supportée
  document.querySelector('body:has(*)')
  console.log('test OK')
} catch {
  console.log('Solution de repli JS pour ".media-extend-menu"')
  const extendMenu = player.querySelector('.media-extend-menu'),
        numberButtons = extendMenu.querySelectorAll('button').length
  let rows = numberButtons
  console.log(rows)
  if (numberButtons > 12) rows = 6
  else if (numberButtons > 6) rows = Math.ceil(numberButtons / 2) // Distribution des boutons sur 2 lignes de manière équitable.
  extendMenu.style.setProperty('--mem', rows)
}


Sujet résolu.
Modifié par Olivier C (01 Jun 2023 - 00:26)