Dlaczego <fieldset> nie może być elastycznymi kontenerami?


200

Próbowałem stylizować fieldsetelement za pomocą display: flexi display: inline-flex.

Jednak to nie zadziałało: flexzachowywał się jak blocki inline-flexzachowywał się jak inline-block.

Dzieje się tak zarówno w przeglądarce Firefox, jak i Chrome, ale dziwnie działa w IE.

Czy to błąd? Nie mogłem znaleźć fieldsetżadnego specjalnego zachowania, ani w HTML5, ani w specyfikacjach CSS Flexible Box Layout .

fieldset, div {
    display: flex;
    border: 1px solid;
}
<fieldset>
    <p>foo</p>
    <p>bar</p>
</fieldset>
<div>
    <p>foo</p>
    <p>bar</p>
</div>


2
Tak, to błąd. Prosta poprawka: użyj innego elementu. code.google.com/p/chromium/issues/detail?id=262679
Adam

Odpowiedzi:


145

Według błędu 984869 - display: flexnie działa w przypadku elementów przycisków ,

<button>nie jest implementowalny (przez przeglądarki) w czystym CSS, więc są trochę czarną skrzynką, z perspektywy CSS. Oznacza to, że niekoniecznie reagują w taki sam sposób, jak np <div>.

Nie dotyczy to Flexboksa - np. Nie renderujemy pasków przewijania, jeśli umieścisz overflow:scrollprzycisk, i nie renderujemy go jako tabeli, jeśli go włożysz display:table.

Cofając się jeszcze bardziej, to nie jest specyficzne <button>. Rozważać <fieldset> i <table> które mają również specjalne zachowanie renderowania:

data:text/html,<fieldset style="display:flex"><div>abc</div><div>def</div>

W takich przypadkach Chrome zgadza się z nami i ignoruje flex tryb wyświetlania. (na co wskazuje fakt, że „abc” i „def” kończą się na stosie w pionie). Fakt, że robią to, czego oczekujesz, <button style="display:flex">jest prawdopodobnie spowodowany szczegółami implementacji.

W implementacji przycisku Gecko kodujemy na stałe <button>(i <fieldset>,i <table>) jako posiadający określoną klasę ramki (a zatem określony sposób układania elementów potomnych), niezależnie od displaywłaściwości.

Jeśli chcesz niezawodnie ustawić dzieci w określonym trybie układu w sposób przeglądarkowy, najlepszym rozwiązaniem jest użycie wrapper-div wewnątrz przycisku, tak jak trzeba w środku a <table>lub<fieldset>.

Dlatego ten błąd został oznaczony jako „rozwiązany nieprawidłowy”.

Istnieje również błąd 1047590 - display: flex;nie działa<fieldset> , obecnie „niepotwierdzony”.


Dobra wiadomość : Firefox 46+ implementuje Flexbox dla <fieldset>. Zobacz błąd 1230207 .


Biorąc pod uwagę, że flexbox jest w zawieszeniu od 8 lat, uważam, że „wyjątkowo” to trochę przesada. Jeśli tak, jestem zaskoczony, że tak szybko działa w przeglądarce Firefox. Może chcesz rzeczy kopnięcia pomoc w biegu na co Google (heh, get it ?).
BoltClock

3
<button> is not implementable (by browsers) in pure CSS- to po prostu złe. Przeglądarka może zaimplementować dowolnie <button>, ale nie jest „umownie zobowiązana” do renderowania jej za pomocą bibliotek widgetów systemowych lub czegokolwiek, co ogranicza zdolność do stylizowania ich za pomocą CSS lub innych niestandardowych zachowań. To samo dotyczy każdego innego elementu.
AMN

4
@BoltClock Nie jestem pewien, co masz na myśli przez zawieszenie. Wszystkie główne przeglądarki obsługują trzecią i ostatnią wersję składni od 2015 r .; myślę, że interoperacyjność jest całkiem dobra. Mamy teraz nawet szerokie wsparcie dla Grid! 🎉
Šime Vidas,

@ Šime Vidas: Rozumiem, wygląda na to, że CR już od roku. Słusznie. Myślałem, że to się nigdy nie uda.
BoltClock

9
2017 rzeczywiście. Gdzie mam skierować swój gniew? Lata oczekiwania na bezpieczne wdrożenie Flexboksa, niezliczone artykuły, tuty, próby / błędy, dostaję 98% i ... zestawy terenowe. To jak poprowadzenie elektryka do okablowania mojego domu, ale okazuje się, że jedno gniazdo zasilania nie jest uziemione. „Nie przesadzaj” Słyszę, że ludzie myślą, przesadzam, ja nie. Dosłownie muszę odpowiedzieć na to jutro. Flex był odpowiedzią na kilka starszych błędów tabeli, które musiałem rozwiązać. Flex jest teraz przyczyną mniejszej liczby błędów spuścizny. Gdzie mam skierować swój gniew?
danjah

20

Dowiaduję się, że może to być błąd w Chrome i Firefox, gdzie legendi fieldsetzamieniane elementy .

Zgłoszone błędy:

Bug Chrome (wciąż otwarty)
Bug Firefox (naprawiony od wersji 46)

Możliwe obejście:

Możliwym obejściem byłoby użycie <div role="group">w HTML i zastosowanie w CSS div[role='group']jako selektorze.


AKTUALIZACJA

W Chrome w wersji 83 button może współpracować z display: inline-grid/grid/inline-flex/flex, możesz zobaczyć demo poniżej:

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


11

Oznacz błąd przeglądarki Chrome, aby zwiększyć priorytet błędu

To jest błąd w Chrome. Dodaj gwiazdkę do tego problemu, aby zwiększyć priorytet, który należy naprawić: https://bugs.chromium.org/p/chromium/issues/detail?id=375693

W międzyczasie stworzyłem te trzy przykłady pióra Code Pen, aby pokazać, jak obejść ten problem. Zostały one zbudowane za pomocą CSS Grid dla przykładów, ale te same techniki mogą być zastosowane dla Flexbox.

Używanie aria-labelledby zamiast legendy

Jest to bardziej odpowiedni sposób na rozwiązanie problemu. Minusem jest to, że musisz poradzić sobie z generowaniem unikalnych identyfikatorów stosowanych do każdego fałszywego elementu legendy.

https://codepen.io/daniel-tonon/pen/vaaGzZ

<style>
.flex-container {
    display: flex;
}
</style>

<fieldset aria-labelledby="fake-legend">
    <div class="flex-container">
        <div class="flex-child" id="fake-legend">
            I am as good accessibilty wise as a real legend
        </div>

        ...

    </div>
</fieldset>

Użycie role = "group" i aria-labelledby zamiast zestawu pól i legendy

Jeśli potrzebujesz elastycznego pojemnika, aby móc rozciągnąć się na wysokość elementu rodzeństwa, a następnie przekazać ten odcinek swoim dzieciom, musisz użyć role="group" zamiast<fieldset>

https://codepen.io/daniel-tonon/pen/BayRjGz

<style>
.flex-container {
    display: flex;
}
</style>

<div role="group" class="flex-container" aria-labelledby="fake-legend">
    <div class="flex-child" id="fake-legend">
        I am as good accessibilty wise as a real legend
    </div>

    ...

</div>

Tworzenie fałszywej duplikaty legendy do celów stylizacji

Jest to o wiele bardziej hackerski sposób na zrobienie tego. Nadal jest tak samo dostępny, ale nie musisz zajmować się identyfikatorami, robiąc to w ten sposób. Główną wadą jest to, że między prawdziwym elementem legendy a fałszywym elementem legendy będzie zduplikowana treść.

https://codepen.io/daniel-tonon/pen/zLLqjY

<style>
.screen-reader-only {
    position: absolute;
    opacity: 0;
    pointer-events: none;
}
.flex-container {
    display: flex;
}
</style>

<fieldset>
    <legend class="screen-reader-only">
        I am a real screen-reader accessible legend element
    </legend>

    <div class="flex-container">
        <div class="flex-child" aria-hidden="true">
            I am a fake legend purely for styling purposes
        </div>

        ...

    </div>
</fieldset>

Legenda MUSI być bezpośrednio przyzwoita

Kiedy po raz pierwszy próbujesz to naprawić, prawdopodobnie spróbujesz to zrobić:

<!-- DO NOT DO THIS! -->
<fieldset>
    <div class="flex-container">
        <legend class="flex-child">
            Broken semantics legend text
        </legend>

        ...

    </div>
</fieldset>

Odkryjesz, że to działa, a następnie prawdopodobnie przejdziesz dalej, nie zastanawiając się dłużej.

Problem polega na tym, że umieszczenie opakowania div między zestawem pól a legendą zrywa związek między dwoma elementami. To łamie semantykę zestawu pól / legend.

Robiąc to, pokonałeś cały cel używania zestawu pól / legend.

Poza tym nie ma sensu używać zestawu pól, jeśli nie nadajesz mu zestawu legend.


9

Z mojego doświadczenia wynika, że <fieldset>ani <button>nie <textarea>mogę , ani nie mogę poprawnie używać display:flexani odziedziczyć właściwości.

Jak już wspomnieli inni, zgłoszono błędy. Jeśli chcesz używać Flexboksa do sterowania kolejnością (np. order:2), Musisz owinąć element w div. Jeśli chcesz, aby Flexbox kontrolował rzeczywisty układ i wymiary, możesz rozważyć użycie div zamiast kontroli wejścia (Które śmierdzi, wiem).


3
<div role="group">
    <p>foo</p>
    <p>bar</p>
</div>
<div>
    <p>foo</p>
    <p>bar</p>
</div>

Może trzeba użyć grupy ról, ponieważ Firefox, Chrome i myślę, że Safari ma błąd z zestawami pól. Wtedy selektor w CSS byłby po prostu

div[role='group'], div {
    display: flex;
    border: 1px solid;
}

Edycja: Oto niektóre problemy, których doświadczają także inni ludzie.

Wydanie 375693

Numer 262679


To wciąż jest problem w Chrome 60.
evolutionxbox

Nadal tutaj w Chrome 66.
Brad

Sprawdzanie Chrome 72.
danemacmillan

Chrome 73 rejestruje się
Michael Draper

Sprawdzanie Chrome 75
xaddict,

3

możesz wstawić dodatkowy div <fieldset>z następującymi rekwizytami:

flex-inner-wrapper {
  display: inherit;
  flex-flow: inherit;
  justify-content: inherit;
  align-items: inherit;
}

1
Nie rozumiem głosów negatywnych. To jest właściwie poprawne. Pamiętaj jednak, aby utrzymać <legend>element (jeśli jest używany) na najwyższym poziomie <fieldset>elementu, aby zachować jego użycie zgodnie z przeznaczeniem ( Permitted content: An optional <legend> element, followed by flow content.- patrz developer.mozilla.org/en-US/docs/Web/HTML/Element/… )
Froxx

2
To nie byłem ja, ale powinienem sobie wyobrazić, że głos głosowania ma coś wspólnego z brakiem odpowiedzi na pytanie. Nie chodziło o znalezienie obejścia, ale o zachowanie fieldsetsamego siebie.
Manngo

Tak, może nie odpowiedzieć bezpośrednio na pytanie (co było nieco filozoficzne), ale jest to możliwe rozwiązanie tego absurdalnego błędu.
Eric S. Bullington,

Głosowanie w dół, ponieważ zachęca do przełamania semantyki <legend>elementu. To w ogóle nie służy celowi użycia zestawu pól / legend. Zobacz moją odpowiedź tutaj: stackoverflow.com/a/59425373/1611058
Daniel Tonon,

3

Aby odpowiedzieć na pierwotne pytanie: tak, jest to błąd, ale w momencie zadawania pytania nie był dobrze zdefiniowany.

Teraz rendering dla zestawu pól jest lepiej zdefiniowany: https://html.spec.whatwg.org/multipage/rendering.html#the-fieldset-and-legend-elements

W przeglądarce Firefox i Safari flexboxnafieldset teraz działa. Nie ma go jeszcze w chromie. (Zobacz https://bugs.chromium.org/p/chromium/issues/detail?id=375693 )

Zobacz także https://blog.whatwg.org/the-state-of-fieldset-interoperability, aby uzyskać informacje na temat ulepszeń wprowadzonych w specyfikacji w 2018 r.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.