Eu codifiquei um script (com a ajuda de um usuário aqui) que me permite expandir uma div selecionada e fazer com que as outras divs se comportem de acordo, esticando igualmente para ajustar o espaço restante (exceto o primeiro cuja largura é fixa).
E aqui está uma imagem do que eu quero alcançar:
Para isso eu uso flex e transitions.
Funciona bem, mas o script jQuery especifica um valor de extensão "400%" (o que é ótimo para teste).
Agora, eu gostaria que a div selecionada fosse expandida / reduzida para se ajustar exatamente ao conteúdo, em vez do valor fixo "400%".
Não tenho ideia de como eu poderia fazer isso.
É possível ?
Tentei clonar a div, ajustá-la ao conteúdo, obter seu valor e, em seguida, usar esse valor para fazer a transição, MAS isso significa que tenho uma largura inicial em porcentagens, mas um valor de destino em pixels. Isso não funciona.
E se eu converter o valor do pixel em porcentagens, o resultado não se ajustará exatamente ao conteúdo por qualquer motivo.
Em todos os casos, essa parece uma maneira um pouco complicada de conseguir o que quero de qualquer maneira.
Não existe nenhuma propriedade flex que possa ser transferida para ajustar o conteúdo de uma div selecionada?
Aqui está o código ( editado / simplificado, para uma melhor leitura ):
var expanded = '';
$(document).on("click", ".div:not(:first-child)", function(e) {
var thisInd =$(this).index();
if(expanded != thisInd) {
//fit clicked fluid div to its content and reset the other fluid divs
$(this).css("width", "400%");
$('.div').not(':first').not(this).css("width", "100%");
expanded = thisInd;
} else {
//reset all fluid divs
$('.div').not(':first').css("width", "100%");
expanded = '';
}
});
.wrapper {
overflow: hidden;
width: 100%;
margin-top: 20px;
border: 1px solid black;
display: flex;
justify-content: flex-start;
}
.div {
overflow: hidden;
white-space: nowrap;
border-right: 1px solid black;
text-align:center;
}
.div:first-child {
min-width: 36px;
background: #999;
}
.div:not(:first-child) {
width: 100%;
transition: width 1s;
}
.div:not(:first-child) span {
background: #ddd;
}
.div:last-child {
border-right: 0px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Click on the div you want to fit/reset (except the first div)
<div class="wrapper">
<div class="div"><span>Fixed</span></div>
<div class="div"><span>Fluid (long long long long long text)</span></div>
<div class="div"><span>Fluid</span></div>
<div class="div"><span>Fluid</span></div>
</div>
Aqui está o jsfiddle:
https://jsfiddle.net/zajsLrxp/1/
EDIT: Aqui está a minha solução de trabalho com a ajuda de todos (tamanhos atualizados no redimensionamento da janela + número de divs e largura da primeira coluna calculada dinamicamente):
var tableWidth;
var expanded = '';
var fixedDivWidth = 0;
var flexPercentage = 100/($('.column').length-1);
$(document).ready(function() {
// Set width of first fixed column
$('.column:first-child .cell .fit').each(function() {
var tempFixedDivWidth = $(this)[0].getBoundingClientRect().width;
if( tempFixedDivWidth > fixedDivWidth ){fixedDivWidth = tempFixedDivWidth;}
});
$('.column:first-child' ).css('min-width',fixedDivWidth+'px')
//Reset all fluid columns
$('.column').not(':first').css('flex','1 1 '+flexPercentage+'%')
})
$(window).resize( function() {
//Reset all fluid columns
$('.column').not(':first').css('flex','1 1 '+flexPercentage+'%')
expanded = '';
})
$(document).on("click", ".column:not(:first-child)", function(e) {
var thisInd =$(this).index();
// if first click on a fluid column
if(expanded != thisInd)
{
var fitDivWidth=0;
// Set width of selected fluid column
$(this).find('.fit').each(function() {
var c = $(this)[0].getBoundingClientRect().width;
if( c > fitDivWidth ){fitDivWidth = c;}
});
tableWidth = $('.mainTable')[0].getBoundingClientRect().width;
$(this).css('flex','0 0 '+ 100/(tableWidth/fitDivWidth) +'%')
// Use remaining space equally for all other fluid column
$('.column').not(':first').not(this).css('flex','1 1 '+flexPercentage+'%')
expanded = thisInd;
}
// if second click on a fluid column
else
{
//Reset all fluid columns
$('.column').not(':first').css('flex','1 1 '+flexPercentage+'%')
expanded = '';
}
});
body{
font-family: 'Arial';
font-size: 12px;
padding: 20px;
}
.mainTable {
overflow: hidden;
width: 100%;
border: 1px solid black;
display: flex;
margin-top : 20px;
}
.cell{
height: 32px;
border-top: 1px solid black;
white-space: nowrap;
}
.cell:first-child{
background: #ccc;
border-top: none;
}
.column {
border-right: 1px solid black;
transition: flex 0.4s;
overflow: hidden;
line-height: 32px;
text-align: center;
}
.column:first-child {
background: #ccc;
}
.column:last-child {
border-right: 0px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<span class="text">Click on the header div you want to fit/reset (except the first one which is fixed)</span>
<div class="mainTable">
<div class="column">
<div class="cell"><span class="fit">Propriété</span></div>
<div class="cell"><span class="fit">Artisan 45</span></div>
<div class="cell"><span class="fit">Waterloo 528</span></div>
</div>
<div class="column">
<div class="cell"><span class="fit">Adresse</span></div>
<div class="cell"><span class="fit">Rue du puit n° 45 (E2)</span></div>
<div class="cell"><span class="fit">Chaussée de Waterloo n° 528 (E1)</span></div>
</div>
<div class="column">
<div class="cell"><span class="fit">Commune</span></div>
<div class="cell"><span class="fit">Ixelles</span></div>
<div class="cell"><span class="fit">Watermael-Boitsfort</span></div>
</div>
<div class="column">
<div class="cell"><span class="fit">Ville</span></div>
<div class="cell"><span class="fit">Marche-en-Famenne</span></div>
<div class="cell"><span class="fit">Bruxelles</span></div>
</div>
<div class="column">
<div class="cell"><span class="fit">Surface</span></div>
<div class="cell"><span class="fit">120 m<sup>2</sup></span></div>
<div class="cell"><span class="fit">350 m<sup>2</sup></span></div>
</div>
</div>
E aqui está um exemplo completo no trabalho (estilos + preenchimento + mais dados):
https://jsfiddle.net/zrqLowx0/2/
Obrigado a todos!
fonte
Respostas:
É possível resolvê-lo usando
max-width
ecalc()
.Primeiro, substitua
width: 100%
comflex: 1
os divs em CSS, então eles vão crescer, o que é melhor neste caso. Além disso, use a transição paramax-width
.Agora, temos que armazenar alguns valores relevantes:
divsLength
variável) - 3 neste caso.extraSpace
variável) - 39px neste caso.Com essas duas variáveis, podemos definir um padrão
max-width
(defaultMaxWidth
variável) para todas as divs, além de usá-las posteriormente. É por isso que eles estão sendo armazenados globalmente.O
defaultMaxWidth
écalc((100% - extraSpace)/divsLength)
.Agora, vamos inserir a função click:
Para expandir a div, a largura do texto de destino será armazenada em uma variável chamada
textWidth
e será aplicada à div comomax-width.
ela usa.getBoundingClientRect().width
(uma vez que retorna o valor do ponto flutuante).Para as divs restantes, é criado um
calc()
paramax-width
que será aplicado a elas.É:
calc(100% - textWidth - extraScape)/(divsLength - 1)
.O resultado calculado é a largura que cada div restante deve ter.
Ao clicar na div expandida, ou seja, para retornar ao normal, o padrão
max-width
é aplicado novamente a todos os.div
elementos.Essa abordagem se comporta dinamicamente e deve funcionar em qualquer resolução.
O único valor que você precisa para codificar é a
extraSpace
variávelfonte
Você precisa lidar com as funções width ou calc. O Flexbox teria uma solução.
Para tornar todos os divs iguais (não o primeiro), usamos
flex: 1 1 auto
.Defina regras flex para sua div normal e div selecionada.
transition: flex 1s;
é seu amigo. Para o selecionado, não precisamos de flex grow, então usamosflex: 0 0 auto
;Adicione a classe selecionada sempre que o usuário clicar em uma div. Você também pode usar a alternância para o segundo clique, para salvar os itens selecionados em um mapa e mostrar vários itens selecionados (não com este exemplo de código, é claro).
https://jsfiddle.net/f3ao8xcj/
fonte
Flex transition: Stretch (or shrink) to fit content
é o título da sua pergunta e esta resposta é um exemplo simples de como fazê-lo. É sua responsabilidade encontrar a solução para o seu caso.Após algumas versões de teste, essa parece ser minha solução mais curta e direta.
Tudo o que precisa, essencialmente, a ser feito é ter Flexbox esticar os
<div>
elementos para os seus limites, por padrão, mas quando<span>
clicado, restrição do trecho da<div>
de<span>
largura ...pseudo-código:
when <span> clicked and already toggled then <div> max-width = 100%, reset <span> toggle state
otherwise <div> max-width = <span> width, set <span> toggle state
Dividi o CSS em uma seção 'mecanismo relevante' e 'apenas colírio para os olhos' para facilitar a leitura (e a reciclagem de código).
O código é muito comentado, então não há muito texto aqui ...
Quirk De alguma forma, há um atraso extra
transition
ao alternardiv
de demax-width: 100%
paramax-width = span width
. Eu verifiquei esse comportamento no Chrome, Edge, IE11 e Firefox (todos os W10) e todos parecem ter essa peculiaridade. Ou algum recálculo interno do navegador está acontecendo, ou talvez otransition
tempo seja usado duas vezes ('parece'). Vice-Versa, por incrível que pareça, não há atraso extra.No entanto, com um curto tempo de transição (por exemplo, 150ms, como estou usando agora) esse atraso extra não é / dificilmente perceptível. (Bom para outra pergunta SO ...)
Mostrar snippet de código
ATUALIZAR
Nova versão que redefine todas as outras
<div>
. Eu realmente odeio o jumpiness, mas isso é devido ao alongamento do Flexbox e aotransition
valor. Semtransition
saltos visíveis. Você precisa experimentar o que funciona para você.Eu adicionei apenas
document.querySelectorAll()
o código javascript.Mostrar snippet de código
fonte