<fieldset> thay đổi kích thước sai; dường như có `min-width: min-content`


221

Vấn đề

Tôi có một <select>trong những <option>giá trị văn bản của nó rất dài. Tôi muốn <select>thay đổi kích thước để nó không bao giờ rộng hơn cha mẹ của nó, ngay cả khi nó phải cắt bỏ văn bản hiển thị của nó. max-width: 100%nên làm điều đó

Trước khi thay đổi kích thước:

trang trước khi thay đổi kích thước, hiển thị toàn bộ <code> chọn </ code>

Những gì tôi muốn sau khi thay đổi kích thước:

trang mong muốn của tôi sau khi thay đổi kích thước, với <code> select </ code> cắt nội dung của nó

Nhưng nếu bạn tải ví dụ jsFiddle này và thay đổi kích thước chiều rộng của bảng Kết quả nhỏ hơn chiều rộng của bảng kết quả <select>, bạn có thể thấy rằng lựa chọn bên trong <fieldset>không thể thu nhỏ chiều rộng của nó.

Những gì tôi thực sự nhìn thấy sau khi thay đổi kích thước:

trang hiện tại của tôi sau khi thay đổi kích thước, với thanh cuộn

Tuy nhiên, trang tương đương với <div>thay vì một<fieldset> tỷ lệ đúng. Bạn có thể thấy điều đó và kiểm tra các thay đổi của bạn dễ dàng hơn nếu bạn có một <fieldset><div>bên cạnh nhau trên một trang . Và nếu bạn xóa các <fieldset>thẻ xung quanh , việc thay đổi kích thước sẽ hoạt động. Các <fieldset>thẻ được bằng cách nào đó gây thay đổi kích thước ngang để phá vỡ.

Các <fieldset>hành vi như thể có một quy tắc CSS fieldset { min-width: min-content; }. ( min-contentcó nghĩa là, đại khái, chiều rộng nhỏ nhất không khiến trẻ bị tràn.) Nếu tôi thay thế <fieldset>bằng một <div>bằngmin-width: min-content , nó trông giống hệt nhau. Tuy nhiên, không có quy tắc nào min-contenttrong các kiểu của tôi, trong biểu định kiểu mặc định của trình duyệt hoặc hiển thị trong Trình kiểm tra CSS của Fireorms. Tôi đã cố gắng ghi đè mọi kiểu hiển thị trên Trình <fieldset>kiểm tra CSS của Fireorms và trong biểu mẫu định dạng mặc định của Firefox.css , nhưng điều đó không có ích. Cụ thể ghi đè min-widthwidthkhông làm gì cả.

HTML của fieldset:

<fieldset>
    <div class="wrapper">
        <select id="section" name="section">
            <option value="-1"></option>
            <option value="1501" selected="selected">Sphinx of black quartz, judge my vow. The quick brown fox jumps over the lazy dog.</option>
            <option value="1480">Subcontractor</option>
            <option value="3181">Valley</option>
            <option value="3180">Ventura</option>
            <option value="3220">Very Newest Section</option>
            <option value="1481">Visitor</option>
            <option value="3200">N/A</option>
        </select>
    </div>
</fieldset>

CSS của tôi sẽ hoạt động nhưng không phải là:

fieldset {
    /* hide fieldset-specific visual features: */
    margin: 0;
    padding: 0;
    border: none;
}

select {
    max-width: 100%;
}

Đặt lại các widththuộc tính về mặc định không làm gì:

fieldset {
    width: auto;
    min-width: 0;
    max-width: none;
}

Hơn nữa CSS mà tôi cố gắng và không khắc phục được sự cố :

/* try lots of things to fix the width, with no success: */
fieldset {
    display: block;
    min-width: 0;
    max-width: 100%;
    width: 100%;
    text-overflow: clip;
}

div.wrapper {
    width: 100%;
}

select {
    overflow: hidden;
}

Thêm chi tiết

Vấn đề cũng xảy ra trong ví dụ jsFiddle toàn diện hơn, phức tạp hơn này , tương tự như trang web mà tôi thực sự đang cố gắng khắc phục. Bạn có thể thấy rằng đó <select>không phải là vấn đề - một khối nội tuyến divcũng không thể thay đổi kích thước. Mặc dù ví dụ này phức tạp hơn, tôi cho rằng việc khắc phục cho trường hợp đơn giản ở trên cũng sẽ khắc phục trường hợp phức tạp hơn này.

[Chỉnh sửa: xem chi tiết hỗ trợ trình duyệt bên dưới.]

Một điều tò mò về vấn đề này là nếu bạn đặtdiv.wrapper { width: 50%; } , các <fieldset>điểm dừng tự thay đổi kích thước tại điểm đó thì kích thước đầy đủ <select>sẽ chạm vào cạnh của khung nhìn. Thay đổi kích thước xảy ra như thể <select>width: 100%, mặc dù <select>trông giống như nó có width: 50%.

sau khi thay đổi kích thước với div trình bao bọc băng thông 50%

Nếu bạn cho <select>chính nówidth: 50% , hành vi đó không xảy ra; chiều rộng được thiết lập chính xác.

sau khi thay đổi kích thước với 50% băng thông chọn

Tôi không hiểu lý do cho sự khác biệt đó. Nhưng nó có thể không liên quan.

Tôi cũng tìm thấy bộ câu hỏi HTML tương tự cho phép trẻ em mở rộng vô tận . Người hỏi không thể tìm ra giải pháp và đoán rằng không có giải pháp nào ngoài việc loại bỏ <fieldset>. Nhưng tôi tự hỏi, nếu thực sự không thể làm cho <fieldset>màn hình hiển thị đúng, tại sao vậy? Có gì trong <fieldset>'s đặc tả hoặc mặc định CSS ( như của câu hỏi này ) gây ra hành vi này? Hành vi đặc biệt này có thể được ghi lại ở đâu đó, vì nhiều trình duyệt hoạt động như thế này.

Mục tiêu và yêu cầu cơ bản

Lý do tôi đang cố gắng thực hiện điều này là một phần của việc viết các kiểu di động cho một trang hiện có với một hình thức lớn. Biểu mẫu có nhiều phần và một phần của nó được gói trong a <fieldset>. Trên điện thoại thông minh (hoặc nếu bạn làm cho cửa sổ trình duyệt của mình nhỏ), phần của trang có <fieldset>phần rộng hơn nhiều so với phần còn lại của biểu mẫu. Hầu hết các biểu mẫu đều hạn chế chiều rộng của nó, nhưng phần <fieldset>không có, buộc người dùng phải thu nhỏ hoặc cuộn sang phải để xem tất cả phần đó.

Tôi cảnh giác chỉ đơn giản là xóa <fieldset>, vì nó được tạo trên nhiều trang trong một ứng dụng lớn và tôi không chắc những công cụ chọn nào trong CSS hoặc JavaScript có thể phụ thuộc vào nó.

Tôi có thể sử dụng JavaScript nếu tôi cần và giải pháp JavaScript tốt hơn không có gì. Nhưng nếu JavaScript là cách duy nhất để làm điều này, tôi sẽ tò mò muốn nghe một lời giải thích tại sao điều này không thể chỉ sử dụng CSS và HTML.


Chỉnh sửa: hỗ trợ trình duyệt

Trên trang web, tôi cần hỗ trợ Internet Explorer 8 trở lên (chúng tôi đã bỏ hỗ trợ cho IE7), Firefox mới nhất và Chrome mới nhất. Trang đặc biệt này cũng sẽ hoạt động trên điện thoại thông minh iOS và Android. Hành vi hơi xuống cấp nhưng vẫn có thể sử dụng được chấp nhận cho Internet Explorer 8.

Tôi đã kiểm tra lại ví dụ bị hỏng của tôifieldset trên các trình duyệt khác nhau. Nó thực sự đã hoạt động trong các trình duyệt này:

  • Internet Explorer 8, 9 và 10
  • Trình duyệt Chrome
  • Chrome cho Android

Nó phá vỡ trong các trình duyệt này:

  • Firefox
  • Firefox cho Android
  • Internet Explorer 7

Do đó, trình duyệt duy nhất tôi quan tâm là mã hiện tại bị hỏng là Firefox (trên cả máy tính để bàn và thiết bị di động). Nếu mã được sửa để nó hoạt động trong Firefox mà không bị hỏng trong bất kỳ trình duyệt nào khác, điều đó sẽ giải quyết vấn đề của tôi.

Mẫu HTML trang web sử dụng các nhận xét có điều kiện của Internet Explorer để thêm các lớp như vậy .ie8.oldievào <html>phần tử. Bạn có thể sử dụng các lớp đó trong CSS của mình nếu bạn cần khắc phục sự khác biệt về kiểu dáng trong IE. Các lớp được thêm vào giống như trong phiên bản HTML5 Boilerplate cũ này .


41
xin chúc mừng bài viết tuyệt vời này
Alp

Ví dụ đơn giản của bạn: cung cấp <fieldset>(hoặc div.wrapper) bất kỳ chiều rộng nào nó cần, và select { width:100% }. max-widthdường như cung cấp cho phần tử một số% chiều rộng ban đầu của cha mẹ , sau đó không chia tỷ lệ, trong khi widthkhông chia tỷ lệ với cha mẹ của nó. Tôi nghĩ rằng sẽ làm những gì bạn muốn (nhưng tôi có thể đã hiểu lầm). Trong câu đố phức tạp hơn của bạn, hãy thử cung cấp cho các trường ở cột bên trái một% băng thông và chiều rộng tối thiểu pixel. Sau đó cung cấp cho các trường bên phải 100 - (trường bên trái -% - chiều rộng)% chiều rộng.
Trojan

Tôi chỉ có một suy nghĩ khác: nếu bạn đặt độ rộng tối thiểu của trường là 0 thì sao? Điều đó có thể sẽ không giải quyết được vấn đề, nhưng có lẽ đáng để thử. Bây giờ tôi đang làm việc với một con đường khác, nhưng nếu nó không hoạt động tôi cũng sẽ thử nó
Trojan

Bạn có cần nhãn và trường để ở trên cùng một dòng? Đối với các khung nhìn nhỏ, chúng chồng lên nhau. Tại sao không làm cho nó phản ứng phần nào, và chuyển sang một dòng mới nếu cần thiết?
Trojan

Câu trả lời:


346

Cập nhật (ngày 25 tháng 9 năm 2017)

Các lỗi Firefox mô tả dưới đây được cố định như của Firefox 53 và các liên kết đến câu trả lời này cuối cùng đã được lấy ra từ tài liệu Bootstrap của .

Ngoài ra, lời xin lỗi chân thành của tôi đến những người đóng góp Mozilla đã phải chặn loại bỏ hỗ trợ -moz-documentmột phần do câu trả lời này.

Cách khắc phục

Trong WebKit và Firefox 53+, bạn chỉ cần đặt min-width: 0;trên bộ trường để ghi đè giá trị mặc định của min-content

Tuy nhiên, Firefox có một chút kỳ quặc khi nói đến các trường. Để làm cho điều này hoạt động trong các phiên bản trước, bạn phải thay đổi thuộc displaytính của bộ trường thành một trong các giá trị sau:

  • table-cell (khuyên dùng)
  • table-column
  • table-column-group
  • table-footer-group
  • table-header-group
  • table-row
  • table-row-group

Trong số này, tôi khuyên bạn nêntable-cell . Cả hai table-rowtable-row-groupngăn bạn thay đổi chiều rộng, trong khi table-columntable-column-groupngăn bạn thay đổi chiều cao.

Điều này sẽ (phần nào hợp lý) phá vỡ kết xuất trong IE. Vì chỉ có Gecko mới cần điều này, nên bạn có thể sử dụng chính xác các phần mở rộng CSS độc quyền@-moz-document của Netherone của Mozilla để ẩn nó khỏi các trình duyệt khác:

@-moz-document url-prefix() {
    fieldset {
        display: table-cell;
    }
}

(Đây là bản demo jsFiddle .)


Điều đó sửa chữa mọi thứ, nhưng nếu bạn bất cứ điều gì như tôi, phản ứng của bạn là một cái gì đó giống như

Gì.

một lý do, nhưng nó không đẹp.

Trình bày mặc định của phần tử fieldset là vô lý và về cơ bản là không thể chỉ định trong CSS. Hãy suy nghĩ về nó: đường viền của trường biến mất khi nó bị chồng chéo bởi một yếu tố huyền thoại, nhưng nền vẫn được nhìn thấy! Không có cách nào để tái tạo điều này với bất kỳ sự kết hợp các yếu tố nào khác.

Trên hết, việc triển khai có đầy đủ các nhượng bộ đối với hành vi kế thừa. Một trong số đó là chiều rộng tối thiểu của một bộ trường không bao giờ nhỏ hơn chiều rộng nội tại của nội dung của nó. WebKit cung cấp cho bạn một cách để ghi đè hành vi này bằng cách chỉ định nó trong biểu định kiểu mặc định, nhưng Gecko² tiến thêm một bước và thực thi nó trong công cụ kết xuất .

Tuy nhiên, các thành phần bảng bên trong tạo thành một loại khung đặc biệt trong Tắc kè. Các ràng buộc về chiều đối với các phần tử có các displaygiá trị này được tính trong một đường dẫn mã riêng biệt , hoàn toàn phá vỡ chiều rộng tối thiểu được thi hành được áp đặt trên các trường.

Một lần nữa, lỗi của lỗi này đã được sửa từ Firefox 53, vì vậy bạn không cần hack này nếu bạn chỉ nhắm mục tiêu các phiên bản mới hơn.

Sử dụng có @-moz-documentan toàn không?

Đối với một vấn đề này, có. @-moz-documenthoạt động như dự định trong tất cả các phiên bản Firefox cho đến 53, trong đó lỗi này được sửa.

Đây không phải là tai nạn. Do một phần của câu trả lời này, lỗi giới hạn @-moz-documentđối với biểu định kiểu người dùng / UA đã được thực hiện tùy thuộc vào lỗi bộ trường bên dưới được sửa trước tiên.

Ngoài ra, không sử dụng @-moz-documentđể nhắm mục tiêu Firefox trong CSS của bạn , các tài nguyên khác mặc dù vậy.


Giá trị có thể được bắt đầu. Theo một độc giả, điều này không có tác dụng trong Trình duyệt chứng khoán Android 4.1.2 và có thể các phiên bản cũ khác; Tôi chưa có thời gian để xác minh điều này.

² Tất cả các liên kết đến nguồn Gecko trong câu trả lời này đề cập đến bộ thay đổi 5065fdc12408 , được cam kết vào ngày 29 tháng 7 năm 2013; bạn có thể muốn so sánh các ghi chú với bản sửa đổi gần đây nhất từ ​​Mozilla Central .

Xem ví dụ SO # 953491: Chỉ nhắm mục tiêu Firefox bằng CSSCSS Tricks: CSS hack nhắm mục tiêu Firefox cho các bài viết được tham chiếu rộng rãi trên các trang web có cấu hình cao.


5
Tôi mới nhận thấy rằng bản sửa lỗi đã bị hỏng trong IE, chỉ đến đây và phát hiện ra rằng bạn đã chỉnh sửa trong giải pháp đó. Cảm ơn! Giải pháp hack Gecko hoạt động tốt với tôi trong mỗi trình duyệt.
Rory O'Kane

Đã kéo tóc tôi ra về vấn đề này, nhưng cách khắc phục của bạn là hoàn hảo - ngoại trừ nó dường như chỉ hoạt động trong firefox. Bất kỳ đề xuất cho các trình duyệt khác, đặc biệt là trình duyệt di động? Vấn đề lớn nhất của tôi là thay đổi kích thước do thay đổi định hướng trên thiết bị di động ...
Adriaan Nel

30
Đây là một câu trả lời hoàn toàn tuyệt vời - kỹ lưỡng, nghiên cứu và súc tích. Cảm ơn.
iamkeir

16
Tất nhiên đó là một câu trả lời hoàn toàn tuyệt vời! Tài liệu chính thức của Bootstrap tại đây
Ranhiru Jude Cooray

1
Vâng, tôi không bao giờ biết rằng về các lĩnh vực. Tôi đã học được một cái gì đó ở đây ngày hôm nay.
siêu sáng

11

Vấn đề Safari trên iOS với câu trả lời được chọn

Tôi tìm thấy câu trả lời từ Jordan Gray là đặc biệt hữu ích. Tuy nhiên, nó dường như không giải quyết được vấn đề này trên Safari iOS cho tôi.

Vấn đề đối với tôi chỉ đơn giản là bộ trường không thể có độ rộng tự động nếu phần tử bên trong có chiều rộng tối đa là% width.

Khắc phục sự cố

Đơn giản chỉ cần đặt bộ trường để có chiều rộng 100% của bộ chứa dường như khắc phục được vấn đề này.

Thí dụ

fieldset {
    min-width: 0; 
    width: 100%; 
}

Vui lòng tham khảo các ví dụ dưới đây để biết các ví dụ hoạt động - nếu bạn loại bỏ% width khỏi bộ trường hoặc thay thế nó bằng auto, nó sẽ không tiếp tục hoạt động.

Câu đố | Codepen


1
Đây là một bổ sung tuyệt vời cho vấn đề chung, tôi không nghĩ sẽ thử nghiệm nó trong iOS. :) Tôi gần như nghĩ rằng điều này có thể đáng để bạn hỏi và tự trả lời như một câu hỏi mới. Tôi sẽ cố gắng thực hiện một số thử nghiệm bổ sung trong tuần này và liên kết với câu trả lời này nếu nó hoạt động.
Jordan Gray

3

Tôi đã vật lộn trong nhiều giờ với điều này và về cơ bản, trình duyệt đang áp dụng kiểu tính toán mà bạn cần ghi đè trong CSS của mình. Tôi quên thuộc tính chính xác đang được đặt trên fieldsetcác phần tử so với divs (có lẽ min-width?).

Lời khuyên tốt nhất của tôi là thay đổi thành phần của bạn thành a div, sao chép các kiểu được tính toán từ thanh tra của bạn, sau đó thay đổi thành phần của bạn trở lại fieldsetvà so sánh các kiểu được tính toán để tìm ra thủ phạm.

Mong rằng sẽ giúp.

Cập nhật: Thêm display: table-celltrợ giúp trong các trình duyệt không phải Chrome.


Tôi đã so sánh mọi thuộc tính CSS của fieldsetdivtrên trang này trong Fireorms. Nó không giúp được gì. Trong Fireorms, các thuộc tính duy nhất có giá trị khác nhau là widthperspective-origin. Các widthlà số lượng khác nhau, nhưng fieldset's widthauto, giống như div' s. Và perspective-originđây chỉ là một chức năng của width- 50% trong số đó theo mặc định.
Rory O'Kane

Tuy nhiên, việc so sánh đã giúp một cách nào đó trong Chrome Web Inspector. Tôi phát hiện ra ngay sau khi mở ví dụ của mình rằng nó đang hoạt động trong Chrome! Tôi đã thêm min-width: 0;ví dụ của mình sau khi thử nghiệm trong Chrome, nhưng có vẻ như điều đó đã giải quyết được vấn đề trong Chrome. Thanh tra web nói với tôi rằng Chrome có phong cách min-width: -webkit-min-content;, giống như tôi đã đưa ra giả thuyết. Vì vậy, bây giờ tôi chỉ cần giải quyết vấn đề trong Firefox và có thể các trình duyệt khác mà tôi chưa thử nghiệm.
Rory O'Kane

Vui vì nó đã giúp một chút. Tôi đã có thể giải quyết vấn đề của mình trong các trình duyệt khác bằng "display: cell-cell". Tôi không nghĩ rằng đó không phải là giải pháp tốt nhất, nhưng hy vọng rằng nó hiệu quả với bạn.
phdj

2

.fake-select { white-space:nowrap; }khiến cho fieldset diễn giải .fake-selectphần tử theo chiều rộng ban đầu của nó, thay vì chiều rộng bắt buộc của nó (ngay cả khi ẩn tràn).

Xóa quy tắc đó và thay đổi .fake-selectmax-width:100%để chỉ width:100%và phù hợp tất cả mọi thứ. Thông báo trước là bạn thấy tất cả nội dung của lựa chọn giả mạo, nhưng tôi không nghĩ rằng điều này là quá tệ và bây giờ nó phù hợp với chiều ngang.

Cập nhật: với các quy tắc hiện tại trong fiddle sau (chỉ chứa các lựa chọn thực), con của bộ trường bị giới hạn về độ rộng chính xác. Khác với việc xóa các quy tắc .fake-selectvà sửa các nhận xét (từ // commentđến /* comment */, tôi đã lưu ý các thay đổi trong CSS của fiddle.

Tôi hiểu vấn đề của bạn tốt hơn bây giờ, và fiddle phản ánh một số tiến bộ. Tôi đặt quy tắc mặc định cho tất cả <select>s và dự trữ .xxlargecho những quy tắc bạn biết sẽ rộng hơn 480px (và điều này chỉ hoạt động vì bạn biết chiều rộng #viewportvà có thể thêm lớp thủ công vào những chỗ quá rộng. Chỉ cần một chút thử nghiệm )

Bằng chứng


Bất cứ sửa chữa nào bạn sử dụng phải làm việc trên thực tế <select>. Các trang web thực tế chỉ có <select>s. Vấn đề fake-selectlà phải có các quy tắc bố cục <select>mà không thực sự là một <select>, chỉ để cho thấy rằng hành vi này không phải là lỗi trình duyệt chỉ xảy ra với <select>các yếu tố. Vì vậy, thay đổi phong cách .fake-selectđể ít giống như một <select>mục đích đánh bại.
Rory O'Kane

Tôi đã thay thế .fake-selecthộp bằng một <select>(giống hệt với cái đã có) để chứng minh. Các yếu tố đều bị ràng buộc theo chiều rộng của cha mẹ (ngoại trừ khi bạn nhấp vào nó, thả xuống các tùy chọn, mỗi tùy chọn được hiển thị trên một dòng - nhưng tôi không nghĩ bạn có thể kiểm soát điều đó). Tôi cũng loại bỏ tất cả các quy tắc cho .fake-select. Liệu fiddle hiện tại làm những gì bạn cần?
Trojan

Nó không. width: 100%hoạt động với các menu dài trên trang, nhưng không hoạt động đúng với các menu ngắn. Nó mở rộng các menu ngắn đến toàn bộ chiều rộng của trang, nhưng tôi muốn các menu ngắn giữ chiều rộng ngắn của chúng. Menu nên có chiều rộng tự nhiên của chúng nếu có chỗ, nhưng chiều rộng 100% nếu chúng quá lớn so với bố mẹ chúng. Đó là những gì max-widthphải làm, nhưng không làm trong trường hợp này.
Rory O'Kane

Tôi đã thực hiện thêm một số thay đổi, tách "tất cả <select>s" khỏi "dài <select>s" và bây giờ chỉ hoạt động trên chiều rộng nền.
Trojan

#viewportcũng không có chiều rộng cố định. Đó là lý do tại sao tôi đặt nút Thay đổi kích thước khung nhìn trên trang - để bạn có thể kiểm tra xem mọi thứ có hoạt động cho dù chiều rộng của khung nhìn là bao nhiêu. Giống như .fake-selectlà một thay thế cho một thực tế <select>để thử nghiệm, #viewportlà một thay thế cho một khung nhìn thực sự. (Một khung nhìn của người khác về cơ bản là một cửa sổ trình duyệt). Tôi đã đưa #viewportvào trang để bạn có thể dễ dàng nhìn thấy các yếu tố thoát khỏi chế độ xem, thay vì phải cuộn để xem chúng.
Rory O'Kane
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.