<fieldset> redimensiona errado; parece ter `min-width: min-content 'irremovível

221

Problema

Eu tenho um <select>onde um dos seus <option>valores de texto é muito longo. Quero que o <select>redimensione para que nunca seja mais largo que seu pai, mesmo que precise cortar o texto exibido. max-width: 100%deveria fazer isso.

Antes de redimensionar:

a página antes do redimensionamento, mostrando todo o <code> selecione </code>

O que eu quero depois de redimensionar:

minha página desejada após o redimensionamento, com o <code> select </code> recortando seu conteúdo

Mas se você carregar este exemplo jsFiddle e redimensionar a largura do painel Resultado para ser menor que a largura do <select>, poderá ver que a seleção dentro da <fieldset>falha ao diminuir sua largura.

O que estou vendo após o redimensionamento:

minha página atual após o redimensionamento, com uma barra de rolagem

No entanto, a página equivalente com a em <div>vez de a<fieldset> é dimensionada corretamente. Você pode ver isso e testar suas alterações mais facilmente se tiver um <fieldset>e um <div>ao lado do outro em uma página . E se você excluir as <fieldset>tags ao redor , o redimensionamento funcionará. De <fieldset>alguma forma, a tag está causando o redimensionamento horizontal.

O <fieldset>ato é como se houvesse uma regra CSS fieldset { min-width: min-content; }. ( min-contentsignifica, grosso modo, a menor largura que não causa a transbordamento de uma criança.) Se eu substituir a <fieldset>com uma <div>pormin-width: min-content , ela parecerá exatamente a mesma. No entanto, não há regra min-contentnos meus estilos, na folha de estilo padrão do navegador ou visível no CSS Inspector do Firebug. Tentei substituir todos os estilos visíveis no <fieldset>CSS Inspector do Firebug e na folha de estilo padrão do Firefox forms.css , mas isso não ajudou. Substituindo especificamente min-widthe widthtambém não fez nada.

Código

HTML do conjunto de campos:

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

Meu CSS que deveria estar funcionando, mas não é:

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

select {
    max-width: 100%;
}

Redefinir as widthpropriedades para os padrões não faz nada:

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

CSS adicional no qual tento e não consigo corrigir o problema :

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

Mais detalhes

O problema também ocorre neste exemplo mais abrangente e complicado do jsFiddle , que é mais semelhante à página da Web que estou tentando corrigir. Você pode ver que isso <select>não é o problema - um bloco embutido divtambém falha ao redimensionar. Embora este exemplo seja mais complicado, suponho que a correção para o caso simples acima também conserte esse caso mais complicado.

[Editar: veja os detalhes de suporte do navegador abaixo.]

Uma coisa curiosa sobre esse problema é que, se você definirdiv.wrapper { width: 50%; } , as <fieldset>paradas <select>serão redimensionadas no ponto e o tamanho completo atingirá a borda da viewport. O redimensionamento acontece como se <select>tivesse width: 100%, mesmo que <select>pareça width: 50%.

após redimensionar com div de wrapper de 50% de largura

Se você dar a <select>si mesmowidth: 50% , que o comportamento não ocorre; a largura é simplesmente definida corretamente.

após redimensionar com seleção de 50% de largura

Eu não entendo o motivo dessa diferença. Mas isso pode não ser relevante.

Eu também achei a pergunta muito semelhante HTML fieldset permite que as crianças se expandam indefinidamente . O solicitante não conseguiu encontrar uma solução e acha que não há solução além de remover o <fieldset>. Mas eu estou pensando, se é realmente impossível corrigir a <fieldset>tela, por que isso? O que, em <fieldset>'s especificação ou padrão CSS ( como desta questão ) faz com que este comportamento? Esse comportamento especial provavelmente está documentado em algum lugar, pois vários navegadores funcionam assim.

Objetivo e requisitos em segundo plano

O motivo pelo qual estou tentando fazer isso é como parte da criação de estilos para dispositivos móveis em uma página existente em formato grande. O formulário possui várias seções, e uma parte dele está envolvida em um <fieldset>. Em um smartphone (ou se você reduzir a janela do navegador), a parte da página com <fieldset>é muito maior que o restante do formulário. A maior parte do formulário restringe sua largura, mas a seção com <fieldset>não, forçando o usuário a diminuir o zoom ou rolar para a direita para ver toda a seção.

Tenho o cuidado de simplesmente remover o <fieldset>, pois ele é gerado em muitas páginas em um aplicativo grande, e não tenho certeza de quais seletores em CSS ou JavaScript podem depender dele.

Eu posso usar JavaScript se precisar, e uma solução JavaScript é melhor que nada. Mas se o JavaScript é a única maneira de fazer isso, ficaria curioso para ouvir uma explicação sobre por que isso não é possível usando apenas CSS e HTML.


Editar: suporte ao navegador

No site, preciso oferecer suporte ao Internet Explorer 8 e posterior (acabamos de deixar o suporte para o IE7), o Firefox mais recente e o Chrome mais recente. Esta página em particular também deve funcionar em smartphones iOS e Android. O comportamento levemente degradado, mas ainda utilizável, é aceitável para o Internet Explorer 8.

Testei novamente meu fieldsetexemplo quebrado em diferentes navegadores. Na verdade, ele já funciona nesses navegadores:

  • Internet Explorer 8, 9 e 10
  • cromada
  • Chrome para Android

Ele quebra nesses navegadores:

  • Raposa de fogo
  • Firefox para Android
  • Internet Explorer 7

Assim, o único navegador que me interessa é o Firefox (no computador e no celular). Se o código fosse corrigido e funcionasse no Firefox sem quebrá-lo em outros navegadores, isso resolveria o meu problema.

O modelo HTML do site usa comentários condicionais do Internet Explorer para adicionar classes como .ie8e .oldieao <html>elemento. Você pode usar essas classes em seu CSS se precisar solucionar as diferenças de estilo no IE. As classes adicionadas são as mesmas da versão antiga do HTML5 Boilerplate .

Rory O'Kane
fonte
41
parabéns a este excelente artigo
Alp
Seu exemplo simples: forneça <fieldset>(ou div.wrapper) a largura que for necessária e select { width:100% }. max-widthparece fornecer ao elemento uma parte da largura original de seu pai , depois não é dimensionado, enquanto que widthé dimensionado com seu pai. Eu acho que vai fazer o que você quer (mas eu poderia ter entendido mal). No seu violino mais complexo, tente dar aos campos da coluna esquerda uma largura de% e uma largura de pixel mínima. Em seguida, forneça os campos à direita 100 - (campos da esquerda -% - largura)% de largura.
Trojan
Acabei de ter outro pensamento: e se você definir a largura mínima do fieldset como 0? Isso por si só provavelmente não resolverá o problema, mas possivelmente vale a pena tentar resolver. Eu estou trabalhando por um caminho diferente agora, mas se isso não funcionar eu vou tentar isso também
Trojan
Você precisa do rótulo e do campo para permanecer na mesma linha? Para pequenas viewports, elas se sobrepõem. Por que não torná-lo um pouco responsivo e mudar para uma nova linha, se necessário?
Trojan

Respostas:

346

Atualização (25 de setembro de 2017)

O bug do Firefox descrito abaixo foi corrigido no Firefox 53 e o link para esta resposta foi finalmente removido da documentação do Bootstrap .

Além disso, minhas sinceras desculpas aos colaboradores da Mozilla que tiveram que bloquear a remoção do suporte para -moz-document parte devido a esta resposta.

O conserto

No WebKit e Firefox 53+, você acabou de definir min-width: 0;no fieldset para substituir o valor padrão demin-content

Ainda assim, o Firefox é um pouco ... estranho quando se trata de conjuntos de campos. Para fazer isso funcionar em versões anteriores, você deve alterar a displaypropriedade do conjunto de campos para um dos seguintes valores:

  • table-cell (recomendado)
  • table-column
  • table-column-group
  • table-footer-group
  • table-header-group
  • table-row
  • table-row-group

Destes, eu recomendotable-cell . Ambos table-rowe table-row-groupimpedi-lo de mudar de largura, enquanto que table-columnetable-column-group impedir a alteração de altura.

Isso (um tanto razoavelmente) interromperá a renderização no IE. Como apenas o Gecko precisa disso, é possível usar justificadamente @-moz-document- uma das extensões CSS proprietárias da Mozilla - para ocultá-lo de outros navegadores:

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

(Aqui está uma demonstração do jsFiddle .)


Isso conserta as coisas, mas se você é como eu, sua reação foi algo como ...

O que.

Não é uma razão, mas não é bonito.

A apresentação padrão do elemento fieldset é absurda e essencialmente impossível de especificar em CSS. Pense bem: a borda do fieldset desaparece onde se sobrepõe a um elemento de legenda, mas o fundo permanece visível! Não há como reproduzir isso com qualquer outra combinação de elementos.

Para completar, as implementações estão cheias de concessões ao comportamento herdado. Uma delas é que a largura mínima de um conjunto de campos nunca é menor que a largura intrínseca de seu conteúdo. O WebKit oferece uma maneira de substituir esse comportamento, especificando-o na folha de estilo padrão, mas o Gecko² vai além e o impõe no mecanismo de renderização .

No entanto, os elementos internos da tabela constituem um tipo de quadro especial no Gecko. Restrições dimensionais para elementos com esses displayvalores definidos são calculadas em um caminho de código separado , contornando completamente a largura mínima imposta imposta aos conjuntos de campos.

Novamente - o bug para isso foi corrigido no Firefox 53, então você não precisa desse hack se estiver apenas visando versões mais recentes.

O uso é @-moz-documentseguro?

Para esta questão, sim. @-moz-documentfunciona como planejado em todas as versões do Firefox até 53, onde esse bug foi corrigido.

Isso não é acidente. Em parte devido a esta resposta, o bug para limitar @-moz-documentas folhas de estilo do usuário / UA ficou dependente do bug do fieldset subjacente que foi corrigido primeiro.

Além disso, não use @-moz-documento Firefox como alvo no seu CSS , apesar de outros recursos.³


¹ O valor pode ser prefixado. Segundo um leitor, isso não tem efeito no Android 4.1.2 Stock Browser e possivelmente em outras versões antigas; Não tive tempo de verificar isso.

² Todos os links para a fonte Gecko nesta resposta se referem ao 5065fdc12408 changeset , confirmado em 29 de julho de 2013; você pode comparar as notas com a revisão mais recente do Mozilla Central .

³ Veja, por exemplo, SO # 953491: segmentando apenas o Firefox com CSS e truques CSS: hacks CSS direcionados ao Firefox para artigos amplamente referenciados em sites de alto perfil.

Jordan Grey
fonte
5
Acabei de perceber que a correção foi interrompida no IE, apenas para vir aqui e descobrir que você já editou a solução para isso. Obrigado! A solução Gecko hack funciona bem para mim em cada navegador.
Rory O'Kane
Estava arrancando meu cabelo com esse problema, mas sua correção é perfeita - exceto que parece funcionar apenas no Firefox. Alguma sugestão para outros navegadores, especialmente navegadores móveis? O meu maior problema é o redimensionamento devido à mudança de orientação em dispositivos móveis ...
Adriaan Nel
30
Esta é uma resposta absolutamente excelente - completa, pesquisada e concisa. Obrigado.
Iamkeir
16
Claro que é uma resposta absolutamente excelente! A documentação oficial do Bootstrap aponta aqui
Ranhiru Jude Cooray /
1
Bem, eu nunca soube disso sobre conjuntos de campos. Eu aprendi algo aqui hoje.
superluminary
11

Problema no Safari no iOS com resposta selecionada

Achei a resposta de Jordan Gray particularmente útil. No entanto, não pareceu resolver esse problema no Safari iOS para mim.

O problema para mim é simplesmente que o fieldset não pode ter uma largura automática se o elemento tiver uma largura máxima como% de largura.

Correção para problema

Simplesmente definir o fieldset para ter uma largura de 100% de seu contêiner parece contornar esse problema.

Exemplo

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

Consulte o exemplo abaixo para exemplos de trabalho - se você remover a largura% do conjunto de campos ou substituí-lo por automático, ele não continuará funcionando.

JSFiddle | Codepen

javalis
fonte
1
Este é um ótimo complemento para o problema geral, não pensei em testá-lo no iOS. :) Eu quase acho que isso pode valer a pena você perguntar e responder como uma nova pergunta também. Vou tentar fazer alguns testes extras esta semana e vincular a esta resposta, se funcionar.
Jordan Grey
3

Eu lutei por muitas horas com isso e, basicamente, o navegador está aplicando um estilo computado que você precisa substituir no seu CSS. Eu esqueço a propriedade exata que está sendo definida nos fieldsetelementos versus divs (talvez min-width?).

Meu melhor conselho seria alterar seu elemento para a div, copiar os estilos computados do seu inspetor e, em seguida, alterar seu elemento novamente fieldsete comparar os estilos computados para encontrar o culpado.

Espero que ajude.

Atualização: a adição de display: table-cellajuda em navegadores não Chrome.

phdj
fonte
Comparei cada propriedade CSS do fieldsete divsobre esta página no Firebug. Isso não ajudou. No Firebug, as únicas propriedades com valores diferentes eram widthe perspective-origin. O widthfoi numericamente diferentes, mas os fieldset's widthera auto, como os div' s. E o perspective-originé apenas uma função dos width- 50% dele por padrão.
Rory O'Kane
No entanto, a comparação ajudou de certa forma no Chrome Web Inspector. Descobri logo após abrir o meu exemplo que ele está funcionando no Chrome! Eu adicionei o min-width: 0;meu exemplo depois de testar no Chrome, mas parece que isso resolveu o problema no Chrome. O Web Inspector me diz que o Chrome tem o estilo min-width: -webkit-min-content;, como eu imaginei. Então agora só preciso resolver o problema no Firefox e possivelmente em outros navegadores em que ainda não testei.
Rory O'Kane
Ainda bem que ajudou um pouco. Consegui resolver meu problema em outros navegadores com "display: table-cell". Não acho que essa não seja a melhor solução, mas espero que funcione para você.
Phdj
2

.fake-select { white-space:nowrap; }fez com que o fieldset interpretasse o .fake-selectelemento pela largura original, e não pela largura forçada (mesmo quando o estouro está oculto).

Retirar essa regra, e mudança .fake-selecté max-width:100%para apenas width:100%e fits tudo. A ressalva é que você vê todo o conteúdo do falso-select, mas não acho que isso seja tão ruim e se encaixa horizontalmente agora.

Atualização: com as regras atuais no violino a seguir (que contém apenas seleções reais), os filhos do fieldset são restritos a corrigir larguras. Além de remover regras .fake-selecte corrigir comentários (de // commentpara /* comment */, observei alterações no CSS do violino.

Compreendo melhor o seu problema agora, e o violino reflete algum progresso. Eu defino regras padrão para todos os se <select>reservo .xxlargepara aqueles que você sabe que terão mais de 480px (e isso só funciona porque você conhece a largura de #viewport, e pode adicionar manualmente a classe àqueles muito grandes. Requer apenas um pouco de teste )

Prova

Trojan
fonte
Qualquer que seja a correção que você use, precisa funcionar de maneira real <select>. O site atual possui apenas <select>s. O objetivo fake-selectera ter as regras de layout de a <select>sem realmente ser a <select>, apenas para mostrar que esse comportamento não é um bug do navegador que acontece apenas com <select>elementos. Então, mudar os estilos de .fake-selectser menos parecido com um <select>derrota o objetivo.
Rory O'Kane
Eu substituí o .fake-select caixa por uma <select>(idêntica à que já está presente) para demonstrar. Os elementos estão todos restritos à largura do pai (exceto quando você clica nele, suspensa as opções, que são exibidas em uma única linha - mas acho que você não pode controlar isso). Também removi todas as regras para .fake-select. O violino atual faz o que você precisa?
Trojan
Isso não. width: 100%funciona com os menus longos da página, mas não funciona corretamente com menus curtos. Ele expande menus curtos para toda a largura da página, mas eu quero que menus curtos mantenham sua largura curta. Os menus devem ter a largura natural, se houver espaço, mas 100% de largura, se forem grandes demais para os pais. Isso é o que max-widthdeveria fazer, mas não o faz neste caso.
Rory O'Kane
Fiz mais algumas alterações, separando "all <select>s" de "long <select>s" e agora trabalhando apenas na largura do plano de fundo.
Trojan
#viewporttambém não possui uma largura fixa. É por isso que eu coloquei o botão Redimensionar viewport na página - para que você possa testar se tudo funciona, independentemente da largura da viewport. Assim como.fake-select é um substituto para um real <select>para testes, #viewporté um substituto para uma viewport real. (Uma "janela de visualização" é basicamente uma janela do navegador). Incluí #viewportna página para que você pudesse ver facilmente os elementos que ficam fora da janela de visualização, em vez de precisar rolar para vê-los.
Rory O'Kane