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

221

проблема

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

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

страница перед изменением размера, показывающая весь <code> select </ code>

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

желаемую страницу после изменения размера, когда <code> select </ code> обрезает ее содержимое

Но если вы загрузите этот пример jsFiddle и измените ширину панели «Результат», чтобы она была меньше ширины панели « <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-инспекторе Firebug. Я пытался переопределить все стили, видимые <fieldset>в CSS-инспекторе Firebug и в стандартной таблице стилей 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, который должен работать, но не работает:

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%

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

после изменения размера с 50% -й шириной выберите

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

Я также нашел очень похожий вопрос: набор полей HTML позволяет детям расширяться до бесконечности . Запрашивающий не смог найти решение и догадывается, что нет другого решения, кроме как удалить <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

Это ломается в этих браузерах:

  • Fire Fox
  • 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 - (left-fields -% - width)% width.
Троян
У меня просто была другая мысль: что если вы установите min-width поля setset равным 0? Это само по себе, вероятно, не решит проблему, но, возможно, стоит попытаться решить. Сейчас я работаю по другому пути, но если это не сработает, я тоже попробую
Trojan
Вам нужен ярлык и поле, чтобы остаться на одной линии? Для небольших областей просмотра они перекрываются. Почему бы не сделать его более отзывчивым и, при необходимости, перейти на новую линию?
Троян,

Ответы:

346

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

Ошибка Firefox , описанная ниже, исправлена в Firefox 53 и ссылка на этот ответ, наконец , была удалена из документации Bootstrap в .

Кроме того, мои искренние извинения авторам Mozilla, которым пришлось заблокировать удаление поддержки -moz-documentчастично из-за этого ответа.

Исправление

В WebKit и Firefox 53+ вы просто устанавливаете min-width: 0;на fieldset переопределение значения по 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одно из собственных CSS-расширений Mozilla, чтобы скрыть его от других браузеров:

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

(Вот демоверсия jsFiddle .)


Это все исправляет, но если вы похожи на меня, ваша реакция была примерно такой ...

Какой.

Там является причиной, но это не красиво.

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

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

Однако внутренние элементы таблицы составляют особый тип фрейма в 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 прекрасно работает в каждом браузере.
Рори О'Кейн
Вытаскивал мои волосы из-за этой проблемы, но твое решение идеально, за исключением того, что оно работает только в Firefox. Любые предложения для других браузеров, особенно для мобильных браузеров? Моя самая большая проблема - изменение размера из-за изменения ориентации на мобильных устройствах ...
Adriaan Nel
30
Это абсолютно превосходный ответ - тщательный, проработанный и лаконичный. Спасибо.
iamkeir
16
Конечно, это превосходный ответ! Официальная документация Bootstrap указывает здесь
Ranhiru Джуд Курай
1
Ну, я никогда не знал этого о наборах полей. Я узнал кое-что здесь сегодня.
Сверхсветовой
11

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

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

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

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

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

пример

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

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

JSFiddle | Codepen

кабанов
источник
1
Это отличное дополнение к общей проблеме, я не думал тестировать ее в iOS. :) Я почти думаю, что это может стоить того, чтобы вы задавали вопросы и отвечали как новый вопрос. Я попытаюсь провести дополнительное тестирование на этой неделе и сошлюсь на этот ответ, если он сработает.
Джордан Грей
3

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

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

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

Обновление: добавление display: table-cellсправки в браузерах без Chrome.

phdj
источник
Я сравнил каждое свойство CSS fieldsetи divна этой странице в Firebug. Это не помогло. В Firebug единственными свойствами с разными значениями были widthи perspective-origin. widthЧисленно различны, но fieldset's widthбыл auto, как div-х гг. И perspective-originэто только функция width- 50% от этого по умолчанию.
Рори О'Кейн,
Однако сравнение в некотором смысле помогло в Chrome Web Inspector. Сразу после открытия моего примера я узнал, что он работает в Chrome! Я добавил min-width: 0;к своему примеру после тестирования в Chrome, но похоже, что это решило проблему в Chrome. Веб-инспектор говорит мне, что у Chrome есть стиль min-width: -webkit-min-content;, как я и предполагал. Так что теперь мне нужно решить проблему только в Firefox и, возможно, в других браузерах, в которых я еще не тестировал.
Рори О'Кейн
Рад, что это немного помогло. Мне удалось решить мою проблему в других браузерах с помощью «display: table-cell». Я не думаю, что это не лучшее решение, но надеюсь, что оно вам подходит.
phdj
2

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

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

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

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

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

троянский
источник
Какое бы исправление вы не использовали, оно должно работать на самом деле <select>. Фактический сайт имеет только <select>с. Смысл fake-selectбыл в том, чтобы иметь правила компоновки, а <select>не быть на самом деле <select>, просто чтобы показать, что это не ошибка браузера, которая возникает только с <select>элементами. Таким образом, изменение стилей, .fake-selectчтобы быть менее похожим на <select>поражение цели.
Рори О'Кейн
Я заменил .fake-selectкоробку <select>(идентичной уже существующей) для демонстрации. Все элементы ограничены шириной родительского элемента (за исключением случаев, когда вы щелкаете по нему, опуская опции, каждый из которых отображается в одной строке - но я не думаю, что вы можете это контролировать). Я также удалил все правила для .fake-select. Делает ли текущая скрипка то, что вам нужно?
Троянец
Это не. width: 100%работает с длинными меню на странице, но не работает с короткими меню. Он расширяет короткие меню на всю ширину страницы, но я хочу, чтобы короткие меню сохраняли свою короткую ширину. Меню должно быть их естественной ширины, если есть место, но 100% ширины, если они слишком велики для своих родителей. Это то, что max-widthдолжно делать, но не в этом случае.
Рори О'Кейн
Я сделал еще несколько изменений, отделяя «все <select>s» от «длинных <select>s», и теперь просто работаю с шириной фона.
Троян
#viewportтакже не имеет фиксированной ширины. Вот почему я поместил кнопку Resize Viewport на странице, чтобы вы могли проверить, что все работает, независимо от ширины области просмотра. Точно так же, как .fake-selectзамена реального <select>тестирования, #viewportзамена реального окна просмотра. («Окно просмотра» - это в основном окно браузера). Я включил #viewportна странице, чтобы вы могли легко видеть элементы, которые торчат из области просмотра, вместо того, чтобы прокручивать, чтобы увидеть их.
Рори О'Кейн