Bố cục Flex / Grid không hoạt động trên các phần tử nút hoặc bộ trường


91

Tôi đang cố gắng căn giữa các yếu tố bên trong của thẻ <button>-tag bằng flexbox justify-content: center. Nhưng Safari không tập trung vào chúng. Tôi có thể áp dụng cùng một kiểu cho bất kỳ thẻ nào khác và nó hoạt động như dự định (xem <p>-tag). Chỉ có nút được căn trái.

Hãy thử Firefox hoặc Chrome và bạn có thể thấy sự khác biệt.

Có bất kỳ kiểu tác nhân người dùng nào mà tôi phải ghi đè không? Hoặc bất kỳ giải pháp nào khác cho vấn đề này?

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>

Và một jsfiddle: http://jsfiddle.net/z3sfwtn2/2/


Câu trả lời:


132

Vấn đề

Trong một số trình duyệt, <button>phần tử không chấp nhận các thay đổi đối với displaygiá trị của nó , ngoài việc chuyển đổi giữa blockinline-block. Điều này có nghĩa là một <button>phần tử không thể là một vùng chứa linh hoạt hoặc lưới, hoặc một <table>trong hai.

Ngoài <button>các phần tử, bạn có thể thấy ràng buộc này cũng áp dụng cho <fieldset><legend>các phần tử.

Xem các báo cáo lỗi bên dưới để biết thêm chi tiết.

Lưu ý: Mặc dù chúng không thể là vùng chứa linh hoạt, nhưng <button>các phần tử có thể là các mục linh hoạt.


Giải pháp

Có một giải pháp đơn giản và dễ dàng trên nhiều trình duyệt cho vấn đề này:

Gói nội dung của buttontrong một spanvà tạo spanhộp chứa linh hoạt.

HTML được điều chỉnh ( buttonnội dung được bao bọc trong 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 được điều chỉnh (được nhắm mục tiêu span)

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

Bản trình diễn sửa đổi


Tài liệu tham khảo / Báo cáo lỗi

Flexbox trên một <button>khối chặn nội dung nhưng không thiết lập bối cảnh định dạng linh hoạt

Người dùng (Oriol Brufau): Phần tử con của <button>nó bị chặn, vì nó ra lệnh cho thông số flexbox. Tuy nhiên, <button>dường như thiết lập một ngữ cảnh định dạng khối thay vì một ngữ cảnh linh hoạt.

Người dùng (Daniel Holbert): Đó thực sự là những gì mà đặc tả HTML yêu cầu. Một số phần tử vùng chứa HTML là "đặc biệt" và có hiệu quả bỏ qua displaygiá trị CSS của chúng trong Gecko [ngoại trừ việc nó ở cấp nội tuyến so với cấp khối]. <button>là một trong số này. <fieldset>& <legend>cũng như vậy.

Thêm hỗ trợ cho hiển thị: bố cục flex / lưới và tập hợp cột bên trong <button>các phần tử

Người dùng (Daniel Holbert):

<button>không thể triển khai (bởi các trình duyệt) trong CSS thuần túy, vì vậy chúng là một hộp đen, theo quan điểm của CSS. Điều này có nghĩa là chúng không nhất thiết phải phản ứng theo cùng một cách mà ví dụ a <div> sẽ làm.

Điều này không dành riêng cho flexbox - ví dụ: chúng tôi không hiển thị thanh cuộn nếu bạn đặt overflow:scrollmột nút và chúng tôi không hiển thị nó dưới dạng bảng nếu bạn đặt display:tablenó.

Lùi lại xa hơn nữa, điều này không dành riêng cho <button>. Hãy xem xét <fieldset><table>cái nào cũng có hành vi kết xuất đặc biệt.

Và các phần tử HTML lâu đời thích <button><table><fieldset>chỉ đơn giản là không hỗ trợ các displaygiá trị tùy chỉnh , ngoài mục đích trả lời câu hỏi cấp cao là "phần tử này là cấp khối hay cấp nội tuyến", để đưa nội dung khác xung quanh phần tử .

Cũng thấy:


3
Tôi hiểu tại sao nó có thể không hoạt động cho <button>s, nhưng tại sao trên trái đất nó không hoạt động cho <fieldset>cả hai? Phần tử đó có nên được coi là một phần tử cấp khối thông thường hợp lệ cho vùng chứa linh hoạt không?
fritzmg

3
@fritzmg. Đã đồng ý. Quy tắc có thể đã tồn tại trước các công nghệ CSS3, chẳng hạn như Flex và Grid, và cần được đánh giá lại.
Michael Benjamin

Vì vậy, chúng tôi muốn ngăn một nút bị lạm dụng ... nhưng vẫn có thể sử dụng sai thứ khác và đặt nó vào bên trong nút. Nghe có vẻ logic như phần còn lại của web ...
Romain Vincent

1
@Michael_B Cân nhắc thêm tham chiếu vào văn bản thực tế nơi bạn đưa ra khẳng định. Không cần trả lời nhận xét của tôi - nếu bạn thêm nó vào văn bản nơi bạn khẳng định, tôi sẽ ủng hộ cho bạn.
mikemaccana

2
A divkhông thể là con của một buttonbởi vì, nếu bạn nghĩ về nó trong HTML kiểu cũ, thì một phần tử cấp khối không thể là con của một phần tử cấp nội tuyến. Nhưng ngày nay, với HTML5, câu trả lời đúng về mặt kỹ thuật là một buttonphần tử chỉ có thể chấp nhận Phrasing Content . A spanđại diện cho Phrasing Content , nhưng a divthì không. A divđại diện cho Nội dung dòng . Thêm chi tiết
Michael Benjamin


1

Khởi động Chrome 83, buttonhiện đã hoạt động như cũ inline-grid/grid/inline-flex/flex, bạn có thể xem thêm về tính năng mới này tại đây

Đây là một đoạn mã (dành cho những người sử dụng Chrome 83 trở lên)

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">

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.