Les dispositions Flex / Grid ne fonctionnent pas sur les éléments de bouton ou de jeu de champs

91

<button>J'essaye de centrer les éléments internes d'un -tag avec flexbox justify-content: center. Mais Safari ne les centre pas. Je peux appliquer le même style à toutes les autres balises et cela fonctionne comme prévu (voir le <p>-tag). Seul le bouton est aligné à gauche.

Essayez Firefox ou Chrome et vous verrez la différence.

Dois-je remplacer un style d'agent utilisateur? Ou toute autre solution à ce problème?

div {
  display: flex;
  flex-direction: column;
  width: 100%;
}
button, p {
  display: flex;
  flex-direction: row;
  justify-content: center;
}
<div>
  <button>
    <span>Test</span>
    <span>Test</span>
  </button>
  <p>
    <span>Test</span>
    <span>Test</span>
  </p>
</div>

Et un jsfiddle: http://jsfiddle.net/z3sfwtn2/2/

Ingemar
la source
Problème
Oriol

Réponses:

132

Le problème

Dans certains navigateurs, l' <button>élément n'accepte pas les modifications de sa displayvaleur, au-delà du basculement entre blocket inline-block. Cela signifie qu'un <button>élément ne peut pas être un conteneur flex ou grid, ou a <table>, non plus.

En plus des <button>éléments, vous trouverez peut - être cette contrainte à appliquer <fieldset>et les <legend>éléments, aussi bien.

Voir les rapports de bogue ci-dessous pour plus de détails.

Remarque: bien qu'ils ne puissent pas être des conteneurs flexibles, les <button>éléments peuvent être des éléments flexibles.


La solution

Il existe une solution de contournement simple et facile entre les navigateurs à ce problème:

Enveloppez le contenu du buttondans un spanet créez le spanconteneur flexible.

HTML ajusté ( buttoncontenu enveloppé dans un span)

<div>
    <button>
        <span><!-- using a div also works but is not valid HTML -->
            <span>Test</span>
            <span>Test</span>
        </span>
    </button>
    <p>
        <span>Test</span>
        <span>Test</span>
    </p>
</div>

CSS ajusté (ciblé span)

button > span, p {
    display: flex;
    flex-direction: row;
    justify-content: center;
}

Démo révisée


Références / rapports de bogues

Flexbox sur un <button>bloque le contenu mais n'établit pas de contexte de formatage flexible

Utilisateur (Oriol Brufau): Les enfants de <button>sont bloqués, comme le dicte la spécification de la flexbox. Cependant, le <button>semble établir un contexte de formatage de bloc au lieu d'un contexte flexible.

Utilisateur (Daniel Holbert): C'est effectivement ce qu'exige la spécification HTML. Plusieurs éléments de conteneur HTML sont "spéciaux" et ignorent effectivement leur displayvaleur CSS dans Gecko [à part si c'est au niveau en ligne ou au niveau du bloc]. <button>en fait partie. <fieldset>& le <legend>sont aussi.

Ajout de la prise en charge de l'affichage: disposition flex / grille et jeu de colonnes à l'intérieur <button> éléments

Utilisateur (Daniel Holbert):

<button>n'est pas implémentable (par les navigateurs) en CSS pur, ils sont donc un peu une boîte noire, du point de vue du CSS. Cela signifie qu'ils ne réagissent pas nécessairement de la même manière qu'un<div> ferait.

Ce n'est pas spécifique à flexbox - par exemple, nous ne rendons pas les barres de défilement si vous placez overflow:scrollun bouton, et nous ne le rendons pas sous forme de tableau si vous le mettez display:table.

Pour revenir encore plus loin, ce n'est pas spécifique à <button>. Considérez <fieldset>et <table>qui ont également un comportement de rendu spécial.

Et les anciens éléments HTML tels que <button>et <table>et <fieldset>ne prennent tout simplement pas en charge les displayvaleurs personnalisées , sauf pour répondre à la question de très haut niveau "est-ce que cet élément est au niveau du bloc ou en ligne", pour faire circuler d'autres contenus autour de l'élément .

Regarde aussi:

Michael Benjamin
la source
3
Je comprends pourquoi cela pourrait ne pas fonctionner pour <button>s, mais pourquoi diable ne fonctionne-t-il pas pour l'un <fieldset>ou l'autre? Cet élément ne devrait-il pas être considéré comme un élément de niveau bloc régulier qui est valide pour un conteneur flex?
fritzmg
3
@fritzmg. D'accord. La règle préexiste probablement aux technologies CSS3, telles que Flex et Grid, et devrait être réévaluée.
Michael Benjamin
Nous aimerions donc éviter qu'un bouton ne soit mal utilisé ... mais nous pourrions quand même abuser de quelque chose d'autre et le placer à l'intérieur du bouton. Cela semble aussi logique que le reste du Web ...
Romain Vincent
1
@Michael_B Pensez à ajouter une référence au texte réel où vous faites l'assertion. Pas besoin de répondre à mon commentaire - si vous l'ajoutez au texte où vous faites l'affirmation, je vous donnerai un vote favorable.
mikemaccana
2
A divne peut pas être un enfant de a buttoncar, si vous y pensez en HTML à l'ancienne, un élément de niveau bloc ne peut pas être un enfant d'un élément de niveau en ligne. Mais aujourd'hui, avec HTML5, la réponse techniquement correcte est que un buttonélément ne peut accepter que le contenu Phrasing . A spanreprésente le contenu de phrasé , mais divpas a. A divreprésente le contenu du flux . Plus de détails
Michael Benjamin
12

Voici mon hack le plus simple.

button::before,
button::after {
    content: '';
    flex: 1 0 auto;
}
Igari Takeharu
la source
Ça ne marche pas pour moi. Comment résoudre ce problème: codepen.io/nuthinking/pen/…
Nuthinking
1

À partir de Chrome 83, le buttonfonctionne maintenant comme inline-grid/grid/inline-flex/flex, vous pouvez en savoir plus sur cette nouvelle fonctionnalité ici

Voici un extrait (pour ceux qui utilisent Chrome 83 et plus)

button {
  display: inline-flex;
  height: 2rem;
  align-items: flex-end;
  width: 4rem;
  -webkit-appearance: none;
  justify-content: flex-end;
}
<!-- 

The align-items keyword should fail in Chrome 81 or earlier, but work in Chrome 83 or later. To see the error, the button needs styles that make it more of an extrinsic container. In other words, it needs a height or width set. 
 
-->
<button>Hi</button>
<input type="button" value="Hi">

dippas
la source