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

Проблема

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

Перед изменением размера:

the page before resize, showing the whole <code>select</code>

Что я хочу после изменения размера:

my desired page after resize, with the <code>select</code> clipping its contents

Но если вы загрузите этот пример jsFiddle и измените размер ширины панелей результатов меньше, чем на <select>, вы можете видеть, что выбор внутри <fieldset> не позволяет уменьшить его ширину.

Что я действительно вижу после изменения размера:

my current page after resize, with a scroll bar

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

Действия <fieldset> выглядят так, как будто существует правило CSS fieldset { min-width: min-content; }. (min-content означает грубую наименьшую ширину, которая не приводит к переполнению дочернего элемента.) Если я заменил <fieldset> на <div> с min-width: min-content, он выглядит точно так же. Тем не менее, нет правила с min-content в моих стилях, в таблице стилей по умолчанию в браузере или в Firebugs CSS Inspector. Я попытался переопределить каждый стиль, видимый в <fieldset> в Firebugs CSS Inspector и в таблице стилей по умолчанию Firefox forms.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, который должен работать, но isnt:

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, который больше похож на веб-страницу Im, фактически пытающуюся исправить. Вы можете видеть из этого, что <select> не проблема - встроенный блок div также не может изменять размер. Хотя этот пример более сложный, я предполагаю, что исправление для простого вышеизложенного случая также устранит этот более сложный случай.

[Изменить: см. ниже сведения о поддержке браузера.]

Любознательная вещь об этой проблеме заключается в том, что если вы установили div.wrapper { width: 50%; }, <fieldset> перестает изменять размер в точке, тогда полная -size <select> ударил бы край окна просмотра. Изменение размера происходит так, как будто <select> имеет width: 100%, хотя <select> выглядит как width: 50%.

after resize with 50%-width wrapper div

Если предоставить <select> сам width: 50%, это поведение не происходит; ширина просто устанавливается правильно.

after resize with 50%-width select

Я не понимаю причину этой разницы. Но это может быть не актуально.

Я также нашел очень похожий вопрос HTML-поле позволяет детям неограниченно расширяться. Ответчик не смог найти решение и догадывается, что нет решения, кроме удаления <fieldset>. Но Im интересно, если действительно невозможно сделать отображение <fieldset> правильным, почему? Что в <fieldset> s spec или CSS по умолчанию вызывает такое поведение? Это особое поведение, вероятно, где-то задокументировано, так как работают несколько браузеров.

Основная цель и требования

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

Не забудьте просто удалить <fieldset>, поскольку он создан на многих страницах большого приложения, и я не уверен, что на нем могут зависеть селекторы в CSS или JavaScript.

Я могу использовать JavaScript, если мне нужно, и решение для JavaScript лучше, чем ничего. Но если JavaScript - единственный способ сделать это, Id будет любопытно услышать объяснение, почему это невозможно, используя только CSS и HTML.


Изменить: поддержка браузера

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

Я протестировал мой сломанный fieldset пример в разных браузерах. Он фактически работает в этих браузерах:

  • Internet Explorer 8, 9 и 10
  • Chrome
  • Chrome для Android

Он разбивается в этих браузерах:

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

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

Шаблон HTML-сайта использует условные комментарии Internet Explorer для добавления классов .ie8 и .oldie к элементу <html>. Вы можете использовать эти классы в своем CSS, если вам нужно обойти различия стилей в IE. Добавленные классы такие же, как в эта старая версия HTML5 Boilerplate.

Ответ 1

Обновление (25 сентября 2017 г.)

К моему большому облегчению, ошибка Firefox, описанная ниже, исправлена ​​с Firefox 53, и ссылка на этот ответ наконец-то была удален из документации Bootstrap.

Исправление

В WebKit и Firefox 53+ вы просто установите min-width: 0; в наборе полей, чтобы переопределить значение по умолчанию min-content

Тем не менее, 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 -one Собственные расширения CSS Mozilla - чтобы скрыть его от других браузеров:

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

(Здесь jsFiddle demo.)


Это исправляет вещи, но если вы что-то вроде меня, ваша реакция была чем-то вроде...

Что.

Есть причина, но это не очень.

По умолчанию представление элемента fieldset абсурдно и по существу невозможно указать в CSS. Подумайте об этом: граница fieldset исчезает там, где она перекрывается элементом легенды, но фон остается видимым! Невозможно воспроизвести это с помощью любой другой комбинации элементов.

В довершение всего, реализации полны уступок в отношении унаследованного поведения. Одним из таких является то, что минимальная ширина набора полей никогда не меньше, чем внутренняя ширина его содержимого. WebKit дает вам возможность переопределить это поведение, указав его в таблице стилей по умолчанию, но Gecko² продвигается дальше, а применяет его в механизме рендеринга.

Однако внутренние элементы таблицы представляют собой специальный тип фрейма в Gecko. Размерные ограничения для элементов с этими наборами значений display вычисляются в отдельный путь кода, полностью обходя минимальную ширину, наложенную на поля.

Снова - ошибка была исправлена ​​с Firefox 53, так что вам не нужен этот взлом, если вы только нацеливаетесь на новые версии.

Использует @-moz-document безопасно?

Для этой одной проблемы да. @-moz-document работает так, как предполагалось, во всех версиях Firefox вплоть до 53, где эта ошибка исправлена.

Это не случайно. Отчасти из-за этого ответа ошибка в limit @-moz-document для таблиц стилей пользователя /UA была сделана в зависимости от того,.

Помимо этого, я больше не рекомендую использовать @-moz-document исключительно для того, чтобы использовать Firefox в вашем CSS, несмотря на другие ресурсы.³


¹ Значение может быть префиксом. По словам одного читателя, это не влияет на Android 4.1.2 Stock Browser и, возможно, на другие старые версии; У меня не было времени проверить это.

² Все ссылки на источник Gecko в этом ответе относятся к 5065fdc12408 changeet, совершенному 29 июля 2013 года; вы можете сравнить заметки с самой последней версией из Mozilla Central.

³ См., например, SO # 953491: Ориентация только на Firefox с CSS и CSS-трюки: CSS-хаки, ориентированные на Firefox для широко разрекламированных статей на высокопоставленных сайтах.

Ответ 2

Safari для iOS с выбранным ответом

Я нашел ответ от Джордана Грея, чтобы быть особенно полезным. Однако, похоже, он не решил эту проблему для iOS Safari для меня.

Проблема для меня просто в том, что для набора полей не может быть автоматической ширины, если элемент внутри имеет максимальную ширину в% ширины.

Исправить проблему

Просто установка набора полей на 100% ширину контейнера, похоже, обойдет эту проблему.

Пример

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

Пожалуйста, обратитесь к приведенным ниже примерам работы - если вы удалите% width из набора полей или замените его на auto, он не будет продолжать функционировать.

JSFiddle | Codepen

Ответ 3

Ive боролся в течение многих часов с этим, и в основном, браузер применяет вычисляемый стиль, который вам нужно переопределить в вашем CSS. Я забыл точное свойство, которое устанавливается на элементах fieldset по сравнению с div (возможно, min-width?).

Моим лучшим советом было бы изменить ваш элемент на div, скопировать вычисленные стили из вашего инспектора, а затем вернуть элемент обратно в fieldset и сравнить вычисленные стили, чтобы найти виновника.

Надеюсь, что это поможет.

Обновление: Добавление display: table-cell помогает в браузерах, отличных от Chrome.

Ответ 4

.fake-select { white-space:nowrap; } заставлял fieldset интерпретировать элемент .fake-select по его первоначальной ширине, а не по его принудительной ширине (даже когда переполнение скрыто).

Удалите это правило и измените .fake-select max-width:100% на width:100% и все будет соответствовать. Предостережение состоит в том, что вы видите все содержимое поддельного выбора, но я не думаю, что это все так плохо, и теперь оно подходит по горизонтали.

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

Теперь я понимаю вашу проблему лучше, и скрипка отражает некоторый прогресс. Я устанавливаю правила по умолчанию для всех <select> s, а зарезервировать .xxlarge для тех, которые, как вы знаете, будут шире 480 пикселей (и это работает только потому, что вы знаете) ширину #viewport и можете вручную добавьте класс в слишком широкий. Просто нужно немного тестирования)

Доказательство