Tata letak Flex / Grid tidak berfungsi pada tombol atau elemen fieldset

91

Saya mencoba untuk memusatkan elemen dalam dari <button>-tag dengan flexbox's justify-content: center. Tapi Safari tidak memusatkannya. Saya dapat menerapkan gaya yang sama ke tag lain dan berfungsi sebagaimana mestinya (lihat <p>-tag). Hanya tombol yang rata kiri.

Coba Firefox atau Chrome dan Anda dapat melihat perbedaannya.

Apakah ada gaya agen pengguna yang harus saya timpa? Atau solusi lain untuk masalah ini?

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>

Dan jsfiddle: http://jsfiddle.net/z3sfwtn2/2/

Ingemar
sumber

Jawaban:

132

Masalah

Di beberapa browser, <button>elemen tidak menerima perubahan pada displaynilainya, selain beralih antara blockdan inline-block. Ini berarti bahwa <button>elemen tidak bisa menjadi wadah flex atau grid, atau <table>keduanya.

Selain <button>unsur-unsur, Anda mungkin menemukan kendala ini berlaku untuk <fieldset>dan <legend>elemen, juga.

Lihat laporan bug di bawah untuk lebih jelasnya.

Catatan: Meskipun tidak bisa menjadi wadah fleksibel, <button>elemen bisa menjadi item fleksibel.


Solusinya

Ada solusi lintas-browser yang sederhana dan mudah untuk masalah ini:

Bungkus isi buttondalam a span, dan buat spanwadah fleksibel.

HTML yang disesuaikan (dibungkus buttonkonten dalam 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>

CSS yang disesuaikan (bertarget span)

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

Demo Revisi


Referensi / Laporan Bug

Flexbox pada suatu <button>memblokir konten tetapi tidak membuat konteks pemformatan fleksibel

Pengguna (Oriol Brufau): Anak-anak dari <button>diblokir, seperti yang ditentukan oleh spesifikasi flexbox. Namun, <button>tampaknya membuat konteks pemformatan blok daripada yang fleksibel.

Pengguna (Daniel Holbert): Itulah yang dibutuhkan spesifikasi HTML. Beberapa elemen penampung HTML bersifat "khusus" dan secara efektif mengabaikan displaynilai CSS-nya di Gecko [selain dari apakah itu tingkat sebaris vs. tingkat blok]. <button>adalah salah satunya. <fieldset>& <legend>juga.

Tambahkan dukungan untuk tampilan: flex / grid dan tata letak kolom di dalam <button>elemen

Pengguna (Daniel Holbert):

<button>tidak dapat diimplementasikan (oleh browser) dalam CSS murni, jadi itu adalah kotak hitam, dari perspektif CSS. Ini berarti bahwa mereka tidak selalu bereaksi dengan cara yang sama seperti misalnya keinginan <div> .

Ini tidak spesifik untuk flexbox - misalnya kami tidak membuat scrollbar jika Anda meletakkan overflow:scrolltombol, dan kami tidak membuatnya sebagai tabel jika Anda meletakkannya display:table.

Melangkah mundur lebih jauh, ini tidak spesifik <button>. Pertimbangkan <fieldset>dan <table>yang juga memiliki perilaku rendering khusus.

Dan elemen HTML lama seperti <button>dan <table>dan <fieldset>tidak mendukung displaynilai khusus , selain untuk menjawab pertanyaan tingkat tinggi "apakah elemen ini tingkat blok atau tingkat sebaris", untuk mengalirkan konten lain di sekitar elemen .

Lihat juga:

Michael Benjamin
sumber
3
Saya mengerti mengapa itu mungkin tidak berhasil untuk <button>s, tetapi mengapa itu tidak berhasil <fieldset>juga? Bukankah elemen itu harus dianggap sebagai elemen tingkat blok biasa yang valid untuk wadah fleksibel?
fritzmg
3
@bayu_joo Sepakat. Aturan tersebut mungkin sudah ada sebelumnya teknologi CSS3, seperti Flex dan Grid, dan harus dievaluasi ulang.
Michael Benjamin
Jadi kami ingin mencegah tombol disalahgunakan ... tetapi masih dapat menyalahgunakan sesuatu yang lain dan meletakkannya di dalam tombol. Kedengarannya sama logisnya dengan web lainnya ...
Romain Vincent
1
@Michael_B Pertimbangkan untuk menambahkan referensi ke teks sebenarnya tempat Anda membuat pernyataan. Tidak perlu membalas komentar saya - jika Anda menambahkannya ke teks tempat Anda membuat pernyataan, saya akan memberi Anda suara positif.
mikemaccana
2
A divtidak bisa menjadi anak dari buttonkarena, jika Anda memikirkannya di HTML jadul, elemen level blok tidak bisa menjadi anak dari elemen level sebaris. Tapi hari ini, dengan HTML5, jawaban yang benar secara teknis adalah bahwa sebuah buttonelemen hanya dapat menerima ungkapan Konten . A spanmewakili Konten Frase , tetapi a divtidak. A divmewakili Isi Arus . Detail lebih lanjut
Michael Benjamin
12

Ini hack saya yang paling sederhana.

button::before,
button::after {
    content: '';
    flex: 1 0 auto;
}
Igari Takeharu
sumber
Tidak berhasil untuk saya. Bagaimana Anda memperbaikinya: codepen.io/nuthinking/pen/…
Nuthinking
1

Memulai Chrome 83, buttonsekarang berfungsi sebagai inline-grid/grid/inline-flex/flex, Anda dapat melihat lebih banyak tentang fitur baru ini di sini

Berikut ini cuplikan (untuk mereka yang menggunakan Chrome 83 dan lebih tinggi)

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
sumber