<fieldset> змінює розмір неправильно; як видається, має незмінний `min-width: min-content`


221

Проблема

У мене є те, <select>де одне його <option>текстове значення дуже довге. Я хочу, <select>щоб розмір змінився, щоб він ніколи не був ширшим за його батьківський, навіть якщо він повинен вирізати відображений текст. max-width: 100%повинен це зробити.

Перед зміною розміру:

сторінка перед зміною розміру, показуючи весь <code> select </code>

Що я хочу після зміни розміру:

мою потрібну сторінку після зміни розміру, з <code> select </code> відсікаючи її вміст

Але якщо ви завантажите цей приклад jsFiddle і зміните ширину панелі Result, щоб бути меншою, ніж ширину <select>, ви можете побачити, що вибір всередині <fieldset>не вдається зменшити його ширину вниз.

Що я насправді бачу після зміни розміру:

мою поточну сторінку після зміни розміру, з смугою прокрутки

Однак, еквівалентна сторінка <div>замість значень "" "<fieldset> робить масштаб належним чином. Ви можете бачити це і легше перевірити свої зміни, якщо на одній сторінці є один <fieldset>і один <div>поруч . І якщо ви видалите навколишні <fieldset>теги , зміна розміру працює. <fieldset>Тег яким - то чином викликає горизонтальне зміна розміру ламатися.

Ці <fieldset>дії, як якщо є правило CSS fieldset { min-width: min-content; }. ( min-contentЗасоби, грубо кажучи, найменша ширина , яка не викликає дитини до переповнення.) Якщо я замінити <fieldset>з <div>зmin-width: min-content , це виглядає точно так же. Однак min-contentу моїх стилях, у таблиці стилів браузера за замовчуванням немає правила , яке не відображається в CSS Inspector Firebug. Я намагався змінити кожен стиль, помітний <fieldset>у CSS Inspector Firebug та у стилі таблиць стилів Firefox form.css , але це не допомогло. Конкретніше переосмислюючі min-widthі widthнічого не робили

Код

HTML набору полів:

<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, який повинен працювати, але не:

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

select {
    max-width: 100%;
}

Скидання widthвластивостей до значень за замовчуванням не робить нічого:

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

Далі CSS, в якому я намагаюся вирішити проблему :

/* 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;
}

Детальніше

Проблема також виникає в цьому більш всебічному, більш складному прикладі jsFiddle , який більше схожий на веб-сторінку, яку я насправді намагаюся виправити. Звідси видно, що <select>проблема не в цьому - вбудований блок divтакож не змінює розмір. Хоча цей приклад є складнішим, я припускаю, що виправлення простого випадку вище також виправить цей складніший випадок.

[Редагувати: див. Інформацію про підтримку веб-переглядача нижче.]

Цікава річ у цій проблемі полягає в тому, що якщо ви встановитеdiv.wrapper { width: 50%; } , <fieldset>зупинки змінюють розмір себе в точці, то повнорозмірний розмір <select>би потрапив на край вікна перегляду. Змінення розміру відбувається так, ніби <select>має width: 100%, хоч і <select>виглядає так, як воно має width: 50%.

після зміни розміру з 50% шириною оболонки Div

Якщо ви даєте <select>себеwidth: 50% , така поведінка не відбувається; ширина просто правильно встановлена.

після зміни розміру з 50% шириною виберіть

Я не розумію причини такої різниці. Але це може не бути актуальним.

Я також виявив, що дуже подібне запитання HTML fieldset дозволяє дітям розширюватися на невизначений час . Запитуючий не зміг знайти рішення і здогадується, що немає рішення, крім видалення <fieldset>. Але мені цікаво, якщо дійсно неможливо зробити <fieldset>дисплей правильним, чому це так? Що в <fieldset>«S специфікації або по замовчуванням CSS ( від цього питання ) викликає таку поведінку? Ця особлива поведінка, ймовірно, десь задокументована, оскільки кілька браузерів працюють так.

Основна мета та вимоги

Причина, яку я намагаюся зробити це, є частиною написання мобільних стилів для існуючої сторінки з великою формою. Форма має кілька розділів, і одна її частина загорнута в <fieldset>. На смартфоні (або якщо ви зробите вікно веб-переглядача невеликим) частина сторінки із <fieldset>значком набагато ширше, ніж решта форми. Більша частина форми просто добре обмежує її ширину, але розділ із <fieldset>знаком "Не", змушує користувача зменшити масштаб або прокрутити праворуч, щоб побачити весь цей розділ.

Я з обережністю просто видаляю <fieldset>цей файл, оскільки він генерується на багатьох сторінках у великому додатку, і я не впевнений, що від цього можуть залежати селектори в CSS або JavaScript.

Я можу використовувати JavaScript, якщо потрібно, і рішення JavaScript краще, ніж нічого. Але якщо JavaScript - єдиний спосіб зробити це, мені буде цікаво почути пояснення, чому це неможливо, використовуючи лише CSS та HTML.


Редагувати: підтримка браузера

На сайті мені потрібно підтримувати Internet Explorer 8 і пізніші версії (ми лише відмовилися від підтримки IE7), останню Firefox та найновішу версію Chrome. Ця конкретна сторінка також має працювати на смартфонах iOS та Android. Невелика деградація, але все ж корисна поведінка прийнятна для Internet Explorer 8.

Я повторно перевірив свій розбитий fieldsetприклад у різних браузерах. Він фактично вже працює в цих браузерах:

  • Internet Explorer 8, 9 та 10
  • Хром
  • Chrome для Android

Це перерви в цих браузерах:

  • Firefox
  • Firefox для Android
  • Internet Explorer 7

Таким чином, єдиний браузер, який мене хвилює, про те, що поточний код вривається, - це Firefox (як на робочому столі, так і на мобільному пристрої). Якщо код було виправлено, щоб він працював у Firefox, не порушуючи його в інших браузерах, це вирішило б мою проблему.

Шаблон HTML сайту використовує умовні коментарі Internet Explorer для додавання таких класів .ie8і .oldieдо <html>елемента. Ви можете використовувати ці класи у своєму CSS, якщо вам потрібно подолати відмінності стилів у IE. Додані класи такі ж, як у цій старій версії HTML5 Boilerplate .


41
вітаємо з цим чудовим записом
Альп

Ваш простий приклад: наведіть <fieldset>(або div.wrapper) будь-яку ширину, яку вона потребує, і select { width:100% }. max-widthяк видається, надає елементу деякий% від початкової ширини свого батька , а потім не масштабує, тоді як widthробить масштаб зі своїм батьківським. Я думаю, що це зробить те, що ти хочеш (але я міг неправильно зрозуміти). У вашій складнішій скрипці спробуйте надати полям у лівому стовпчику% -широку та міні-піксель-ширину. Потім введіть поля праворуч 100 - (ліві поля -% - ширина)% ширини.
Троян

У мене просто була інша думка: що робити, якщо встановити міні-ширину поля на 0? Це само собою, мабуть, не вирішить проблему, але, можливо, варто спробувати розібратися. Зараз я працюю іншим шляхом, але якщо це не вийде, я спробую це теж
Троян

Вам потрібні мітка та поле, щоб залишитися на одній лінії? Для невеликих вікон перегляду вони перекриваються. Чому б не зробити це трохи чуйним, а при необхідності перейти до нового рядка?
Троян

Відповіді:


346

Оновлення (25 вересня 2017 р.)

Помилка Firefox , описана нижче, виправлена в Firefox 53 і посилання на цей відповідь, нарешті , була видалена з документації Bootstrap в .

Також мої щирі вибачення перед учасниками Mozilla, які -moz-documentчастково через цю відповідь повинні були заблокувати видалення підтримки .

Виправлення

У WebKit та Firefox 53+ ви просто встановите набір min-width: 0;поля, щоб замінити значення за замовчуванням. min-contentOf

І все-таки Firefox трохи… дивним, коли мова йде про набори польових програм. Щоб зробити цю роботу в більш ранніх версіях, потрібно змінити displayвластивість набору полів на одне з наступних значень:

  • table-cell (рекомендується)
  • table-column
  • table-column-group
  • table-footer-group
  • table-header-group
  • table-row
  • table-row-group

З них я рекомендуюtable-cell . Як table-rowі table-row-groupзапобігти вас від зміни ширини, в той час як table-columnі table-column-groupзапобігти вас від зміни висоти.

Це (дещо розумно) порушить надання в IE. Оскільки цього потрібен лише Gecko, ви можете виправдано використовувати @-moz-document- одне з власних розширень CSS Mozilla - приховати його від інших браузерів:

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

(Ось демонстрація jsFiddle .)


Це виправляє речі, але якщо ти щось схоже на мене, твоя реакція була чимось на кшталт ...

Що.

Там є причиною, але це не красиво.

Представлення елемента набору полів за замовчуванням є абсурдним і по суті неможливо вказати в CSS. Подумайте над цим: межа поля поля зникає там, де вона перекрита елементом легенди, але фон залишається видимим! Неможливо відтворити це за допомогою будь-якої іншої комбінації елементів.

На додаток до цього, реалізація повна поступок на спадщину. Одне з таких полягає в тому, що мінімальна ширина набору полів ніколи не менша за внутрішню ширину його вмісту. WebKit дає вам змогу змінити таку поведінку, вказавши її в таблиці стилів за замовчуванням, але Gecko² піде на крок далі і застосовує її в механізмі візуалізації .

Однак внутрішні елементи таблиці складають особливий тип кадру у Гекко. Обмеження розмірів для елементів із displayнабором цих значень обчислюються окремим кодовим шляхом , повністю не обходячи примусової мінімальної ширини, накладеної на набори полів.

Знову ж таки - помилка для цього була виправлена ​​як у Firefox 53, тому цей хакер вам не потрібен, якщо ви орієнтуєтесь лише на новіші версії.

Використовується @-moz-documentбезпечно?

Щодо цього питання, так. @-moz-documentпрацює за всіма версіями Firefox до 53, де ця помилка виправлена.

Це не випадково. Частково завдяки цій відповіді помилка для обмеження @-moz-documentтаблиць стилів користувач / UA стала залежною від того, що спочатку виправлена ​​основна помилка набору полів.

Крім цього, не використовуйте @-moz-documentдля націлювання Firefox у своєму CSS , незважаючи на інші ресурси.³


¹ Значення може бути префіксом. За словами одного читача, це не впливає на Android 4.1.2 Stock Browser та, можливо, інші старі версії; Я не встиг це перевірити.

² Усі посилання на джерело Gecko у цій відповіді стосуються набору змін 5065fdc12408 , здійсненого 29 липня 2013 року; ви можете порівняти нотатки з останньою редакцією Mozilla Central .

³ Див., Наприклад, SO # 953491: Націлювання лише на Firefox за допомогою фокусів CSS та CSS: CSS хакує націлювання на Firefox для широко посилаються статей на гучних сайтах.


5
Я щойно помітив, що виправлення зламалося в IE, тільки щоб завітати сюди і дізнатися, що ви вже відредагували рішення в цьому. Дякую! Рішення про злому Gecko для мене добре працює в кожному браузері.
Rory O'Kane

Витягнув моє волосся з цього питання, але ваше виправлення ідеально - хіба що, здається, працює лише у firefox. Будь-які пропозиції щодо інших браузерів, особливо мобільних браузерів? Моя найбільша проблема - зміни розміру через зміну орієнтації на мобільних пристроях ...
Adriaan Nel

30
Це абсолютно чудова відповідь - ретельна, досліджена та лаконічна. Дякую.
iamkeir

16
Звичайно, це абсолютно чудова відповідь! Офіційна документація Bootstrap тут
вказується Ранхіру Джуд Курай

1
Ну, я ніколи не знав цього про польові набори. Я сьогодні щось тут навчився.
надсвіткові

11

Випуск Safari на iOS із вибраною відповіддю

Я знайшов відповідь Джордана Грея особливо корисною. Однак це, схоже, не вирішило цю проблему на Safari iOS для мене.

Проблема для мене полягає лише в тому, що набір полів не може мати автоматичну ширину, якщо елемент всередині має максимальну ширину як% ширина.

Виправлення для випуску

Проста встановлення набору полів таким чином, щоб його контейнер був на 100% шириною, схоже, усуне цю проблему.

Приклад

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

Будь ласка, зверніться до наведених нижче робочих прикладів - якщо ви вилучите% ширину з набору полів або заміните її на автоматичну, вона не продовжить функціонувати.

JSFiddle | Codepen


1
Це чудове доповнення до загальної проблеми, я не думав тестувати її в iOS. :) Я майже думаю, що це також може бути вашим запитанням та самовідповіддю, як новим питанням. Я спробую зробити додаткове тестування на цьому тижні і посилатись на цю відповідь, якщо це працює.
Джордан Грей

3

Я багато років боровся з цим, і, в основному, браузер застосовує обчислювані стилі, які вам потрібно перекрити у своєму CSS. Я забуваю точну властивість, яка встановлюється на fieldsetелементи проти divs (можливо,min-width ?).

Моєю найкращою порадою буде змінити свій елемент на a div, скопіювати обчислені стилі у свого інспектора, а потім змінити елемент назад наfieldset і порівняти обчислені стилі, щоб знайти винуватця.

Сподіваюся, що це допомагає.

Оновлення: Додавання display: table-cellдопомагає у веб-переглядачах, які не входять у Chrome.


Я порівнював усі властивості CSS на fieldsetта divна цій сторінці в Firebug. Це не допомогло. У Firebug єдиними властивостями з різними значеннями були widthі perspective-origin. widthЧисельно різні, але fieldset's widthбув auto, як divх рр. І perspective-originце лише функція width- 50% за замовчуванням.
Rory O'Kane

Однак порівняння допомогло певним чином допомогти веб-інспектору Chrome. Я відразу після відкриття свого прикладу з’ясував, що він працює в Chrome! Я додав min-width: 0;свій приклад після тестування в Chrome, але, схоже, це вирішило проблему в Chrome. Веб-інспектор каже мені, що Chrome має стиль min-width: -webkit-min-content;, як я вважав. Тож зараз мені потрібно лише вирішити проблему у Firefox та, можливо, інших браузерах, на які я ще не тестувався.
Rory O'Kane

Радий, що це мало допомогло. Мені вдалося вирішити свою проблему в інших браузерах з "display: table-cell". Я не думаю, що це не найкраще рішення, але, сподіваюся, це працює для вас.
phdj

2

.fake-select { white-space:nowrap; }змусив набір полів інтерпретувати .fake-selectелемент його початковою шириною, а не примусовою шириною (навіть коли переповнення приховано).

Видаліть це правило, а змініть .fake-selects max-width:100%на справедливе width:100%і все підходить. Застереження полягає в тому, що ви бачите весь вміст фальшивого вибору, але я не думаю, що це все так погано, і це відповідає горизонталі зараз.

Оновлення: діючими правилами в наступній скрипці (яка містить лише реальний вибір) діти поля поля обмежені для корекції ширини. Крім видалення правил .fake-selectта виправлення коментарів (від // commentдо/* comment */ , я зазначив зміни у CSS скрипту.

Зараз я краще розумію вашу проблему, і загадка відображає певний прогрес. Я встановлюю правила за замовчуванням для всіх <select>s, а резерв .xxlargeдля тих, про які ви знаєте, буде ширшим за 480px (і це працює лише тому, що ви знаєте ширину #viewport, і ви можете вручну додати клас до занадто широких. Просто потрібно трохи тестувати )

Доказ


Яке б виправлення ви не використовували, воно має працювати на фактичному <select>. Фактичний сайт має лише <select>s. Сенс fake-selectполягав у тому, щоб встановити правила компонування <select>без того <select>, щоб насправді бути a , просто показати, що ця поведінка не є помилкою браузера, яка трапляється лише з <select>елементами. Тож зміна стилів .fake-selectбути менш схожою на <select>поразку мети.
Rory O'Kane

Я замінив .fake-selectящик на <select>(ідентичний тому, що вже є) для демонстрації. Усі елементи обмежені шириною батьків (за винятком випадків, коли ви клацаєте на неї, випадаючи параметри, які відображаються в одному рядку, але я не думаю, що ви можете це контролювати). Я також видалив усі правила для .fake-select. Чи виконує поточна скрипка те, що потрібно?
Троян

Це не. width: 100%працює з довгими меню на сторінці, але не працює правильно з короткими меню. Це розширює короткі меню на всю ширину сторінки, але я хочу, щоб короткі меню зберігали свою коротку ширину. Меню має бути їх природна ширина, якщо є місце, але 100% ширина, якщо вони занадто великі для свого батька. Це те, що max-widthпотрібно робити, але не робити цього в цьому випадку.
Rory O'Kane

Я вніс ще кілька змін, відокремивши "all <select>s" від "long <select>s", і зараз я працюю лише на ширині фону.
Троян

#viewportне має фіксованої ширини. Ось чому я помістив кнопку Resize Viewport на сторінку - щоб ви могли перевірити, що все працює незалежно від ширини вікна перегляду. Так само, як .fake-selectзаміна реального <select>для тестування, #viewportє замінником реального огляду. ("Перегляд" - це в основному вікно браузера). Я включив #viewportна сторінку, щоб ви могли легко бачити елементи, які стирчать із вікна перегляду, а не прокручувати їх, щоб побачити їх.
Rory O'Kane
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.