J'ai codé un script (avec l'aide d'un utilisateur ici) qui me permet d'agrandir un div sélectionné et de faire en sorte que les autres div se comportent en conséquence en s'étirant également pour s'adapter à l'espace restant (sauf le premier dont la largeur est fixe).
Et voici une photo de ce que je veux réaliser:
Pour cela j'utilise des flex et des transitions.
Cela fonctionne bien, mais le script jQuery spécifie une valeur d'étirement "400%" (ce qui est idéal pour les tests).
Maintenant, je voudrais que le div sélectionné s'agrandisse / rétrécisse pour s'adapter exactement au contenu au lieu de la valeur fixe "400%".
Je ne sais pas comment je pourrais faire ça.
C'est possible ?
J'ai essayé de cloner le div, de l'adapter au contenu, d'obtenir sa valeur et d'utiliser cette valeur pour la transition MAIS cela signifie que j'ai une largeur initiale en pourcentage mais une valeur cible en pixels. Ça ne marche pas.
Et si je convertis la valeur en pixels en pourcentages, le résultat ne correspond pas exactement au contenu pour une raison quelconque.
Dans tous les cas, cela semble un peu compliqué pour réaliser ce que je veux de toute façon.
N'y a-t-il pas une propriété flex qui pourrait être transférée afin de s'adapter au contenu d'un div sélectionné?
Voici le code ( édité / simplifié depuis pour une meilleure lecture ):
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>
Voici le jsfiddle:
https://jsfiddle.net/zajsLrxp/1/
EDIT: Voici ma solution de travail avec l'aide de vous tous (tailles mises à jour lors du redimensionnement de la fenêtre + nombre de divs et largeur de la première colonne calculée dynamiquement):
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>
Et voici un exemple à part entière au travail (styles + rembourrage + plus de données):
https://jsfiddle.net/zrqLowx0/2/
Merci à tous !
la source
Réponses:
Il est possible de le résoudre en utilisant
max-width
etcalc()
.Tout d'abord, remplacez
width: 100%
parflex: 1
pour les divs en CSS, afin qu'ils grandissent, ce qui est mieux dans ce cas. De plus, utilisez transition pourmax-width
.Maintenant, nous devons stocker des valeurs pertinentes:
divsLength
variable) - 3 dans ce cas.extraSpace
variable) - 39px dans ce cas.Avec ces 2 variables, nous pouvons définir une valeur par défaut
max-width
(defaultMaxWidth
variable) pour toutes les divs, ainsi que les utiliser plus tard. C'est pourquoi ils sont stockés dans le monde.Le
defaultMaxWidth
estcalc((100% - extraSpace)/divsLength)
.Maintenant, entrons dans la fonction de clic:
Pour développer le div, la largeur du texte cible sera stockée dans une variable appelée
textWidth
et elle sera appliquée au div telmax-width.
qu'il l'utilise.getBoundingClientRect().width
(car il renvoie la valeur à virgule flottante).Pour les div restants, il est créé un
calc()
pourmax-width
qui leur sera appliqué.Il est:
calc(100% - textWidth - extraScape)/(divsLength - 1)
.Le résultat calculé est la largeur de chaque div restante.
Lorsque vous cliquez sur le div étendu, c'est-à-dire pour revenir à la normale, la valeur par défaut
max-width
est à nouveau appliquée à tous les.div
éléments.Cette approche se comporte de manière dynamique et devrait fonctionner sur n'importe quelle résolution.
La seule valeur dont vous avez besoin pour coder en dur est la
extraSpace
variable.la source
Vous devez gérer les fonctions largeur ou calc. Flexbox aurait une solution.
Pour rendre toutes les div égales (pas la première) que nous utilisons
flex: 1 1 auto
.Définissez des règles de flexion pour votre div normal et votre div sélectionné.
transition: flex 1s;
est votre ami. Pour celui que nous avons sélectionné, nous n'avons pas besoin de flex flex, nous utilisons doncflex: 0 0 auto
;Ajoutez la classe sélectionnée chaque fois que l'utilisateur clique sur une div. Vous pouvez également utiliser la bascule pour le deuxième clic afin de pouvoir enregistrer les éléments sélectionnés dans une carte et vous pouvez afficher plusieurs éléments sélectionnés (pas avec cet exemple de code bien sûr).
https://jsfiddle.net/f3ao8xcj/
la source
Flex transition: Stretch (or shrink) to fit content
est le titre de votre question et cette réponse est un exemple simple de la façon de le faire. Il vous appartient de trouver la solution à votre cas.Après quelques versions d'essai, cela semble être ma solution la plus courte et la plus simple.
Tout ce qui doit essentiellement être fait est d' avoir Flexbox étirer les
<div>
éléments à leurs limites par défaut, mais quand on<span>
clique dessus, contrainte l'étirement de la<div>
à la<span>
largeur ...pseudo code:
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
J'ai divisé le CSS en une section «mécanisme pertinent» et «eye-candy only» pour une lecture facile (et recylage du code).
Le code est fortement commenté, donc pas beaucoup de texte ici ...
Quirk D'une façon ou d'une autre, il y a un délai supplémentaire lors du
transition
passagediv
demax-width: 100%
àmax-width = span width
. J'ai vérifié ce comportement dans Chrome, Edge, IE11 et Firefox (tous W10) et tous semblent avoir cette bizarrerie. Soit un recalcul interne du navigateur est en cours, soit peut-être que letransition
temps est utilisé deux fois («on dirait»). Vice Versa, curieusement, il n'y a pas de délai supplémentaire.Cependant, avec un temps de transition court (par exemple 150 ms, comme je l'utilise actuellement), ce retard supplémentaire n'est pas / à peine perceptible. (Sympa pour une autre question SO ...)
Afficher l'extrait de code
MISE À JOUR
Nouvelle version qui réinitialise tous les autres
<div>
. Je déteste vraiment la nervosité, mais cela est dû à l'étirement de la Flexbox et à satransition
valeur. Sanstransition
aucun saut visible. Vous devez essayer ce qui fonctionne pour vous.J'ai seulement ajouté
document.querySelectorAll()
au code javascript.Afficher l'extrait de code
la source