Zakodowałem skrypt (z pomocą tutaj użytkownika), który pozwala mi rozwinąć wybrany div i sprawić, aby inne div zachowywały się odpowiednio, rozciągając się równo, aby dopasować się do pozostałej przestrzeni (z wyjątkiem pierwszego, którego szerokość jest stała).
A oto zdjęcie tego, co chcę osiągnąć:
Do tego używam flexu i przejść.
Działa dobrze, ale skrypt jQuery określa „400%” wartość rozciągnięcia (co jest świetne do testowania).
Teraz chciałbym, aby wybrany div rozszerzył / zmniejszył, aby dokładnie pasował do zawartości zamiast stałej wartości „400%”.
Nie mam pojęcia, jak to zrobić.
Czy to możliwe ?
Próbowałem sklonować div, dopasować go do treści, uzyskać jego wartość, a następnie użyć tej wartości do przejścia, ALE oznacza to, że mam początkową szerokość w procentach, ale wartość docelową w pikselach. To nie działa.
A jeśli przekonwertuję wartość piksela w procentach, wynik nie pasuje dokładnie do treści z jakiegokolwiek powodu.
We wszystkich przypadkach i tak wydaje się to nieco skomplikowanym sposobem na osiągnięcie tego, czego chcę.
Czy nie ma żadnej właściwości flex, którą można by przenieść, aby dopasować ją do zawartości wybranego div?
Oto kod ( edytowany / uproszczony, ponieważ dla lepszego odczytu ):
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>
Oto jsfiddle:
https://jsfiddle.net/zajsLrxp/1/
EDYCJA: Oto moje działające rozwiązanie z pomocą was wszystkich (rozmiary aktualizowane przy zmianie rozmiaru okna + liczba div i szerokość pierwszej kolumny obliczana dynamicznie):
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>
A oto pełny przykład pracy (style + padding + więcej danych):
https://jsfiddle.net/zrqLowx0/2/
Dziękuję wam wszystkim !
źródło
Odpowiedzi:
Można to rozwiązać za pomocą
max-width
icalc()
.Po pierwsze, należy wymienić
width: 100%
zflex: 1
na div w CSS, więc będą rosnąć, co jest lepsze w tym przypadku. Ponadto użyj przejścia dlamax-width
.Teraz musimy przechowywać pewne istotne wartości:
divsLength
zmienne) - 3 w tym przypadku.extraSpace
zmienna) - w tym przypadku 39 pikseli.Za pomocą tych 2 zmiennych możemy ustawić wartość domyślną
max-width
(defaultMaxWidth
zmienną) dla wszystkich div, a także użyć ich później. Dlatego są one przechowywane na całym świecie.defaultMaxWidth
Jestcalc((100% - extraSpace)/divsLength)
.Teraz przejdźmy do funkcji kliknięcia:
Aby rozwinąć div, szerokość tekstu docelowego zostanie zapisana w zmiennej o nazwie
textWidth
i zostanie zastosowana do div zgodnie zmax-width.
jej użyciem.getBoundingClientRect().width
(ponieważ zwraca wartość zmiennoprzecinkową).Dla pozostałych div, to tworzony jest
calc()
zamax-width
które będą stosowane do nich.To jest:
calc(100% - textWidth - extraScape)/(divsLength - 1)
.Obliczony wynik to szerokość, jaką powinien mieć każdy pozostały div.
Po kliknięciu rozwiniętego div, to znaczy, aby powrócić do normalności, ustawienie domyślne
max-width
jest ponownie stosowane do wszystkich.div
elementów.To podejście zachowuje się dynamicznie i powinno działać na dowolnej rozdzielczości.
Jedyną wartością, której potrzebujesz do twardego kodu, jest
extraSpace
zmienna.źródło
Musisz poradzić sobie z funkcjami szerokości lub obliczania. Flexbox miałby rozwiązanie.
Aby wszystkie div były równe (nie pierwsze), używamy
flex: 1 1 auto
.Zdefiniuj reguły flex dla normalnej div i wybranej div.
transition: flex 1s;
jest twoim przyjacielem. W przypadku wybranych nie potrzebujemy elastycznego wzrostu, więc używamyflex: 0 0 auto
;Dodaj wybraną klasę za każdym razem, gdy użytkownik kliknie div. Możesz także użyć przełącznika dla drugiego kliknięcia, aby zapisać wybrane elementy na mapie i wyświetlić wiele wybranych elementów (oczywiście nie z tym przykładem kodu).
https://jsfiddle.net/f3ao8xcj/
źródło
Flex transition: Stretch (or shrink) to fit content
to tytuł twojego pytania, a ta odpowiedź jest prostym przykładem tego, jak to zrobić. Twoim obowiązkiem jest znaleźć rozwiązanie dla twojej sprawy.Po kilku wersjach próbnych wydaje się to moim najkrótszym i najprostszym rozwiązaniem.
Wszystko, co w zasadzie trzeba zrobić, to domyślnie rozciągnąć
<div>
elementy do ich granic, ale po<span>
kliknięciu ograniczenie rozciągnięcia<div>
do<span>
szerokości ...pseudo kod:
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
Podzieliłem CSS na sekcję „odpowiedni mechanizm” i „tylko cukierki” dla łatwego czytania (i recyklingu kodu).
Kod jest mocno komentowany, więc nie ma tu dużo tekstu ...
Dziwactwo Jakoś występuje dodatkowe opóźnienie w
transition
przełączaniudiv
zmax-width: 100%
namax-width = span width
. Sprawdziłem to zachowanie w Chrome, Edge, IE11 i Firefox (wszystkie W10) i wszystkie wydają się mieć takie dziwactwo. Trwa wewnętrzne przeliczanie przeglądarki, a możetransition
czas jest używany dwukrotnie („wydaje się”). Odwrotnie, co dziwne, nie ma dodatkowego opóźnienia.Jednak przy krótkim czasie przejścia (np. 150 ms, jak teraz używam), to dodatkowe opóźnienie nie jest / prawie nie jest zauważalne. (Miło dla drugiego SO pytanie ...)
Pokaż fragment kodu
AKTUALIZACJA
Nowa wersja, która resetuje wszystkie pozostałe
<div>
. Naprawdę nie lubię bluzy, ale wynika to z rozciągania Flexboksa i jegotransition
wartości. Beztransition
widocznych skoków. Musisz wypróbować, co Ci odpowiada.Dodałem tylko
document.querySelectorAll()
do kodu javascript.Pokaż fragment kodu
źródło