javascript - 柔性过渡 : Stretch (or shrink) to fit content

标签 javascript jquery css flexbox css-transitions

我编写了一个脚本(在用户的帮助下),它允许我扩展选定的 div 并通过均匀拉伸(stretch)以适应剩余空间(除了第一个宽度固定的第一个 div)使其他 div 相应地表现.

这是我想要实现的目标的图片:

enter image description here

为此,我使用了 Flex 和 Transitions。

它运行良好,但 jQuery 脚本指定了“400%”拉伸(stretch)值(这非常适合测试)。

现在我希望所选的 div 能够扩展/收缩以完全适合内容,而不是“400%”固定值。

我不知道如何才能做到这一点。

可能吗?

我尝试克隆 div,将其适合内容,获取其值,然后使用该值进行转换,但这意味着我有一个以百分比为单位的初始宽度,但以像素为单位的目标值。那是行不通的。

如果我将像素值转换为百分比,那么无论出于何种原因,结果都不完全适合内容。

在所有情况下,这似乎是实现我想要的目标的一种有点复杂的方法。

是否没有任何可以转换的 Flex 属性以适应所选 div 的内容?

这是代码(为了更好地阅读而进行了编辑/简化):

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>

这是 jsfiddle:

https://jsfiddle.net/zajsLrxp/1/

编辑:这是我在大家帮助下的工作解决方案(窗口调整大小时更新的大小+ div 数量和动态计算的第一列宽度):

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>

这是一个成熟的工作示例(样式+填充+更多数据):

https://jsfiddle.net/zrqLowx0/2/

谢谢大家!

最佳答案

可以使用max-widthcalc()来解决它。

首先,将 CSS 中的 div 的 width: 100% 替换为 flex: 1,这样它们就会变大,在这种情况下效果更好。此外,对 max-width 使用过渡。

现在,我们必须存储一些相关值:

  • 将进行动画处理的 div 数量(divsLength 变量) - 在本例中为 3。
  • 用于固定 div 和边框的总宽度(extraSpace 变量) - 在本例中为 39px。

通过这两个变量,我们可以为所有 div 设置默认的 max-width (defaultMaxWidth 变量),并在以后使用它们。这就是为什么它们被存储在全局范围内。

defaultMaxWidthcalc((100% - extraSpace)/divsLength)

现在,让我们进入点击函数:

要展开 div,目标文本的宽度将存储在名为 textWidth 的变量中,并将其作为 max-width 应用于 div。使用 .getBoundingClientRect().width (因为它返回浮点值)。

对于剩余的 div,它会为将应用于它们的 max-width 创建一个 calc()
它是:calc(100% - textWidth - extraScape)/(divsLength - 1)
计算的结果就是剩下的每个div应该有的宽度。

当点击展开的 div 时,即恢复正常状态时,默认的 max-width 会再次应用于所有 .div 元素。

var expanded = false,
    divs = $(".div:not(:first-child)"),
    divsLength = divs.length,
    extraSpace = 39, //fixed width + border-right widths 
    defaultMaxWidth = "calc((100% - " + extraSpace + "px)/" + divsLength + ")";

    divs.css("max-width", defaultMaxWidth);

$(document).on("click", ".div:not(:first-child)", function (e) {
  var thisInd = $(this).index();

  if (expanded !== thisInd) {
    
    var textWidth = $(this).find('span')[0].getBoundingClientRect().width;  
    var restWidth = "calc((100% - " + textWidth + "px - " + extraSpace + "px)/" + (divsLength - 1) + ")";
    
    //fit clicked fluid div to its content and reset the other fluid divs 
    $(this).css({ "max-width": textWidth });
    $('.div').not(':first').not(this).css({ "max-width": restWidth });
    expanded = thisInd;
  } else {
    //reset all fluid divs
    $('.div').not(':first').css("max-width", defaultMaxWidth);
    expanded = false;
  }
});
.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) {
  flex: 1;
  transition: max-width 1s;
}

.div:not(:first-child) span {
  background: #ddd;
}

.div:last-child {
  border-right: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.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 text)</span></div>
  <div class="div"><span>Fluid</span></div>
  <div class="div"><span>Fluid</span></div>

</div>

此方法的行为是动态的,并且应该适用于任何分辨率。
您需要硬编码的唯一值是 extraSpace 变量。

关于javascript - 柔性过渡 : Stretch (or shrink) to fit content,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60366886/

相关文章:

javascript - 如何像另一个对象一样构建一个对象?

jquery - 当用户使用 jQuery 将表头滚动到 View 之外时,表头保持固定在顶部

javascript - CSS 转换立即进入最终状态

javascript - 运行 npm install -g yo 命令给出 -> ERR

Javascript在网页上执行js,例如chrome控制台

jquery - "a href"标签没有用 JQuery 动画关闭

css - CSS 高度溢出 :100%?

javascript - 将 “*” 分配给范围内声明的 var 时发生 Angular 错误

javascript - Grunt 不会改变 Bower_components

html - 为 IE8 上的表中的最后一个 td 提供宽度