Flex / Grid-Layouts funktionieren nicht mit Schaltflächen- oder Feldsatzelementen

91

Ich versuche, innere Elemente eines <button>Tags mit Flexboxen zu zentrieren justify-content: center. Aber Safari zentriert sie nicht. Ich kann den gleichen Stil auf alle anderen Tags anwenden und er funktioniert wie vorgesehen (siehe <p>-tag). Nur die Schaltfläche ist linksbündig.

Probieren Sie Firefox oder Chrome aus und Sie können den Unterschied sehen.

Gibt es einen Benutzeragentenstil, den ich überschreiben muss? Oder eine andere Lösung für dieses Problem?

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>

Und eine jsfiddle: http://jsfiddle.net/z3sfwtn2/2/

Ingemar
quelle

Antworten:

130

Das Problem

In einigen Browsern <button>akzeptiert das Element keine Änderungen an seinem displayWert, außer zwischen blockund zu wechseln inline-block. Dies bedeutet, dass ein <button>Element kein Flex- oder Gittercontainer oder auch kein sein kann <table>.

Zusätzlich zu <button>Elementen gilt diese Einschränkung möglicherweise auch für <fieldset>und <legend>Elemente.

Weitere Informationen finden Sie in den Fehlerberichten unten.

Hinweis: Obwohl es sich nicht um Flex-Container handeln kann, können <button>Elemente Flex-Elemente sein.


Die Lösung

Es gibt eine einfache und browserübergreifende Problemumgehung für dieses Problem:

Wickeln Sie den Inhalt des buttonin ein spanund machen Sie spanden Flex-Container.

Angepasster HTML-Code (umschlossener buttonInhalt in a 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>

Angepasstes CSS (gezielt span)

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

Überarbeitete Demo


Referenzen / Fehlerberichte

Flexbox auf einem <button>blockiert den Inhalt, erstellt jedoch keinen Flex-Formatierungskontext

Benutzer (Oriol Brufau): Die Kinder von <button>sind blockiert, wie es die Flexbox-Spezifikation vorschreibt. Es <button>scheint jedoch einen Blockformatierungskontext anstelle eines flexiblen zu erstellen.

Benutzer (Daniel Holbert): Genau das erfordert die HTML-Spezifikation. Einige HTML-Containerelemente sind "speziell" und ignorieren ihren CSS- displayWert in Gecko effektiv [abgesehen davon, ob es sich um Inline-Ebene oder Block-Ebene handelt]. <button>ist einer davon. <fieldset>& <legend>sind auch.

Unterstützung für die Anzeige hinzufügen: Flex / Grid- und Columnset-Layout innerhalb von <button>Elementen

Benutzer (Daniel Holbert):

<button>ist (von Browsern) nicht in reinem CSS implementierbar, daher sind sie aus Sicht von CSS eine Art Black Box. Dies bedeutet, dass sie nicht unbedingt so reagieren, wie z <div> . B. a .

Dies ist nicht spezifisch für Flexbox - z. B. rendern wir keine Bildlaufleisten, wenn Sie overflow:scrolleine Schaltfläche anlegen , und wir rendern sie nicht als Tabelle, wenn Sie sie anbringen display:table.

Wenn Sie noch weiter zurücktreten, ist dies nicht spezifisch für <button>. Berücksichtigen Sie <fieldset>und <table>welche auch spezielles Renderverhalten haben.

Und alt-timey HTML - Elemente wie <button>und <table>und <fieldset>einfach keine benutzerdefinierten unterstützen displayWerte, die nicht für die Zwecke der Beantwortung der auf sehr hohem Niveau Frage „ist dieses Element auf Blockebene oder auf Inline-Ebene“, für fließende andere Inhalte rund um das Element .

Siehe auch:

Michael Benjamin
quelle
3
Ich verstehe, warum es für <button>s vielleicht nicht funktioniert , aber warum um alles in der Welt funktioniert es auch nicht <fieldset>? Sollte dieses Element nicht als reguläres Element auf Blockebene betrachtet werden, das für einen Flex-Container gültig ist?
fritzmg
3
@fritzmg. Einverstanden. Die Regel existiert wahrscheinlich bereits in CSS3-Technologien wie Flex und Grid und sollte neu bewertet werden.
Michael Benjamin
Wir möchten also verhindern, dass ein Knopf missbraucht wird ... könnten aber trotzdem etwas anderes missbrauchen und es in den Knopf legen. Klingt ungefähr so ​​logisch wie der Rest des Webs ...
Romain Vincent
1
@Michael_B Erwägen Sie, einen Verweis auf den tatsächlichen Text hinzuzufügen, in dem Sie die Behauptung aufstellen. Sie müssen nicht auf meinen Kommentar antworten - wenn Sie ihn dem Text hinzufügen, in dem Sie die Behauptung aufstellen, gebe ich Ihnen eine Gegenstimme.
Mikemaccana
2
A divkann kein Kind von a sein, buttondenn wenn Sie es in HTML der alten Schule betrachten, kann ein Element auf Blockebene kein Kind eines Elements auf Inline-Ebene sein. Bei HTML5 lautet die technisch korrekte Antwort heute jedoch, dass ein buttonElement nur Phrasierungsinhalte akzeptieren kann . A steht spanfür Phrasierungsinhalte , a divjedoch nicht. A steht divfür Flow Content . Weitere Details
Michael Benjamin
12

Hier ist mein einfachster Hack.

button::before,
button::after {
    content: '';
    flex: 1 0 auto;
}
Igari Takeharu
quelle
Funktioniert bei mir nicht Wie würden Sie das beheben: codepen.io/nuthinking/pen/…
Nuthinking
1

Ab Chrome 83 buttonfunktioniert das jetzt so inline-grid/grid/inline-flex/flex. Weitere Informationen zu dieser neuen Funktion finden Sie hier

Hier ist ein Ausschnitt (für Benutzer von Chrome 83 und höher)

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
quelle