发布于2023-03-24 16:17 阅读(884) 评论(0) 点赞(14) 收藏(3)
我在编写一些 css/html 元素时遇到了这个问题。一直在网上搜索潜在的解决方案,但似乎没有一个能解决我的问题。
我有一个动态数量的子元素需要适合显示的父元素(弹性容器)。子元素有点像徽章,您可以在其中显示信息。悬停时,子元素应展开宽度过渡并显示一个实用程序图标供我单击。到目前为止一切都很好。问题是悬停时,因为孩子会展开,如果它是 flex 中行的“最后一个”孩子,它将移动到下一行并完全展开,我无法再到达图标。
有什么解决办法吗?我尝试对孩子使用负边距以欺骗它停留在它所在的同一行,但是孩子本身在溢出时被父容器切断了整个身体(它看起来也不太好)。
我还尝试过强制每行只包含 n 个子元素(例如每行 2 个子元素),但这只会减少问题发生的可能性,并不能有效地消除它。
我希望寻找的是保持宽度过渡并允许动态数量的子元素填充到父容器元素中并每行填充尽可能多的子元素(因此 flex 行换行),同时所有子元素都被刷新到左边。
演示(下方)中的“&”是图标;请注意某些行末尾的某些子元素如何在悬停时无法到达它们进入下一行。
.flex-container {
height: 100px;
width: 400px;
overflow-y: auto;
display: flex;
flex-flow: row wrap;
}
.flex-badge {
display: inline-flex;
margin-right: 0.5vw;
margin-bottom: 0.5vh;
background-color: lightblue;
border: 1px solid black;
cursor: pointer;
}
.hiddenIconTray {
display: flex;
overflow: hidden;
width: 0;
transition: width 0.5s;
}
.flex-badge:hover > .hiddenIconTray {
width: 20px;
}
.flex-badge:hover {
background-color: yellow;
}
<div class="flex-container">
<div class="flex-badge">Lorem ipsum dolor sit amet
<div class="hiddenIconTray">
<i class="icon">&</i>
</div>
</div>
<div class="flex-badge">Lorem
<div class="hiddenIconTray">
<i class="icon">&</i>
</div>
</div>
<div class="flex-badge">Lorem
<div class="hiddenIconTray">
<i class="icon">&</i>
</div>
</div>
<div class="flex-badge">Lorem
<div class="hiddenIconTray">
<i class="icon">&</i>
</div>
</div>
<div class="flex-badge">Lorem
<div class="hiddenIconTray">
<i class="icon">&</i>
</div>
</div>
<div class="flex-badge">ipsum dolor sit
<div class="hiddenIconTray">
<i class="icon">&</i>
</div>
</div>
<div class="flex-badge">Lorem ipsum dolor sit amet
<div class="hiddenIconTray">
<i class="icon">&</i>
</div>
</div>
<div class="flex-badge">ipsum dolor sit amet
<div class="hiddenIconTray">
<i class="icon">&</i>
</div>
</div>
<div class="flex-badge">Lorem ipsum dolor sit amet
<div class="hiddenIconTray">
<i class="icon">&</i>
</div>
</div>
<div class="flex-badge">Lorem
<div class="hiddenIconTray">
<i class="icon">&</i>
</div>
</div>
<div class="flex-badge">Lorem ipsum dolor sit amet
<div class="hiddenIconTray">
<i class="icon">&</i>
</div>
</div>
<div class="flex-badge">Lorem ipsum dolor sit amet
<div class="hiddenIconTray">
<i class="icon">&</i>
</div>
</div>
<div class="flex-badge">Lorem
<div class="hiddenIconTray">
<i class="icon">&</i>
</div>
</div>
<div class="flex-badge">ipsum dolor
<div class="hiddenIconTray">
<i class="icon">&</i>
</div>
</div>
<div class="flex-badge">Lorem
<div class="hiddenIconTray">
<i class="icon">&</i>
</div>
</div>
<div class="flex-badge">ipsum dolor
<div class="hiddenIconTray">
<i class="icon">&</i>
</div>
</div>
<div class="flex-badge">Lorem ipsum
<div class="hiddenIconTray">
<i class="icon">&</i>
</div>
</div>
<div class="flex-badge">Lorem ipsum dolor sit amet
<div class="hiddenIconTray">
<i class="icon">&</i>
</div>
</div>
<div class="flex-badge">ipsum dolor
<div class="hiddenIconTray">
<i class="icon">&</i>
</div>
</div>
<div class="flex-badge">Lorem ipsum dolor sit amet
<div class="hiddenIconTray">
<i class="icon">&</i>
</div>
</div>
</div>
谢谢!
在这种情况下,您可以使用一种巧妙的解决方法,即在需要之前分配您想要使用的间距量。
这里需要几个步骤……
flex-badge
元素在展开后可能会换行到下一行,因此我们可以预期可能会添加一个margin-right
我们知道宽度将增加的确切大小的值,您将其设置为20px
. 因为您已经有一些边距来将这些 flex 元素分开,所以我将您的原始边距移动到gap
父级上设置的属性,这是该属性的预期用途。所有现代浏览器 ( caniuse.com )都正式支持这一点。margin
更改,我们还必须考虑这样一个事实,即添加margin-right: 20px
到所有flex-badge
元素会在每个元素之间添加一个不需要的间隙。margin-left: -20px
我们可以通过先发制人地添加所有元素来抵消这种副作用flex-badge
。margin-right
悬停元素上的这个值转换为0
随着元素的子元素填充的空间增加以填充hiddenIconTray
空白而流畅地减少预分配的空间。padding-left: 20px
应用于父元素的 a 配对。就是这样!一个功能齐全的容器,其中元素提前换行到下一行,如果它们在悬停时这样做的话。瞧 ✨
.flex-container {
height: 100px;
width: 400px;
overflow-y: auto;
display: flex;
gap: 0.5vw 0.5vh;
flex-flow: row wrap;
padding-left: 20px;
}
.flex-badge {
display: inline-flex;
background-color: lightblue;
border: 1px solid black;
cursor: pointer;
transition: margin-left 0.5s, margin-right 0.5s;
}
.flex-badge {
margin-left: -20px;
}
.flex-badge {
margin-right: 20px;
}
.hiddenIconTray {
display: flex;
overflow: hidden;
width: 0;
transition: width 0.5s;
}
.flex-badge:hover {
margin-right: 0;
background-color: yellow;
z-index: 1;
}
.flex-badge:hover > .hiddenIconTray {
width: 20px;
}
<div class="flex-container">
<div class="flex-badge">Lorem ipsum dolor sit amet
<div class="hiddenIconTray">
<i class="icon">&</i>
</div>
</div>
<div class="flex-badge">Lorem
<div class="hiddenIconTray">
<i class="icon">&</i>
</div>
</div>
<div class="flex-badge">Lorem
<div class="hiddenIconTray">
<i class="icon">&</i>
</div>
</div>
<div class="flex-badge">Lorem
<div class="hiddenIconTray">
<i class="icon">&</i>
</div>
</div>
<div class="flex-badge">Lorem
<div class="hiddenIconTray">
<i class="icon">&</i>
</div>
</div>
<div class="flex-badge">ipsum dolor sit
<div class="hiddenIconTray">
<i class="icon">&</i>
</div>
</div>
<div class="flex-badge">Lorem ipsum dolor sit amet
<div class="hiddenIconTray">
<i class="icon">&</i>
</div>
</div>
<div class="flex-badge">ipsum dolor sit amet
<div class="hiddenIconTray">
<i class="icon">&</i>
</div>
</div>
<div class="flex-badge">Lorem ipsum dolor sit amet
<div class="hiddenIconTray">
<i class="icon">&</i>
</div>
</div>
<div class="flex-badge">Lorem
<div class="hiddenIconTray">
<i class="icon">&</i>
</div>
</div>
<div class="flex-badge">Lorem ipsum dolor sit amet
<div class="hiddenIconTray">
<i class="icon">&</i>
</div>
</div>
<div class="flex-badge">Lorem ipsum dolor sit amet
<div class="hiddenIconTray">
<i class="icon">&</i>
</div>
</div>
<div class="flex-badge">Lorem
<div class="hiddenIconTray">
<i class="icon">&</i>
</div>
</div>
<div class="flex-badge">ipsum dolor
<div class="hiddenIconTray">
<i class="icon">&</i>
</div>
</div>
<div class="flex-badge">Lorem
<div class="hiddenIconTray">
<i class="icon">&</i>
</div>
</div>
<div class="flex-badge">ipsum dolor
<div class="hiddenIconTray">
<i class="icon">&</i>
</div>
</div>
<div class="flex-badge">Lorem ipsum
<div class="hiddenIconTray">
<i class="icon">&</i>
</div>
</div>
<div class="flex-badge">Lorem ipsum dolor sit amet
<div class="hiddenIconTray">
<i class="icon">&</i>
</div>
</div>
<div class="flex-badge">ipsum dolor
<div class="hiddenIconTray">
<i class="icon">&</i>
</div>
</div>
<div class="flex-badge">Lorem ipsum dolor sit amet
<div class="hiddenIconTray">
<i class="icon">&</i>
</div>
</div>
</div>
There's one last piece of this that still begs more attention. The items now overlap each other rather than pushing and pull each other as they grow and shrink. This is unfortunately unavoidable using only CSS as it is a result of the margin tweaking we performed.
However, if you are open to using a little JavaScript, we can get this working perfectly with the help of a simple loop to add a class to the first element in each flex row so we can style identify those and apply custom styles based on flex-rows rather than flex items. This is a feature not yet supported in CSS, but hopefully down the row, we'll be given with pseudo-classes for flex and grid rows and columns. This paired with the upcoming :has()
pseudo selector would make this possible using only CSS.
We can also make use of the built-in ResizeObserver API, which is supported across all modern browsers (caniuse.com).
Here it is in action:
const flexBadgesContainer = document.querySelector('.flex-container');
const flexBadges = document.querySelectorAll('.flex-badge');
const markFirstOfFlexRows = () => {
let currentOffsetTop = null;
for (const badge of flexBadges) {
if (badge.offsetTop !== currentOffsetTop) {
currentOffsetTop = badge.offsetTop;
badge.classList.add('flex-row-first');
}
}
}
markFirstOfFlexRows();
new ResizeObserver(() => {
for (const badge of flexBadges) badge.classList.remove('flex-row-first');
markFirstOfFlexRows();
}).observe(flexBadgesContainer);
.flex-container {
height: 100px;
width: 400px;
overflow-y: auto;
resize: both;
border: 1px solid #000;
display: flex;
gap: 0.5vw 0.5vh;
flex-flow: row wrap;
padding-left: 20px;
}
.flex-badge {
display: inline-flex;
background-color: lightblue;
border: 1px solid black;
cursor: pointer;
transition: margin-left 0.5s, margin-right 0.5s;
}
.flex-badge {
margin-left: -20px;
}
.flex-badge {
margin-right: 20px;
}
.hiddenIconTray {
display: flex;
overflow: hidden;
width: 0;
transition: width 0.5s;
}
.flex-badge:hover {
margin-right: 0;
background-color: yellow;
z-index: 1;
}
.flex-badge:hover ~ .flex-badge:not(.flex-row-first) {
margin-left: 0;
margin-right: 0;
}
.flex-badge:hover ~ .flex-badge.flex-row-first + .flex-badge {
margin-left: -20px;
}
.flex-badge:hover > .hiddenIconTray {
width: 20px;
}
<div class="flex-container">
<div class="flex-badge">Lorem ipsum dolor sit amet
<div class="hiddenIconTray">
<i class="icon">&</i>
</div>
</div>
<div class="flex-badge">Lorem
<div class="hiddenIconTray">
<i class="icon">&</i>
</div>
</div>
<div class="flex-badge">Lorem
<div class="hiddenIconTray">
<i class="icon">&</i>
</div>
</div>
<div class="flex-badge">Lorem
<div class="hiddenIconTray">
<i class="icon">&</i>
</div>
</div>
<div class="flex-badge">Lorem
<div class="hiddenIconTray">
<i class="icon">&</i>
</div>
</div>
<div class="flex-badge">ipsum dolor sit
<div class="hiddenIconTray">
<i class="icon">&</i>
</div>
</div>
<div class="flex-badge">Lorem ipsum dolor sit amet
<div class="hiddenIconTray">
<i class="icon">&</i>
</div>
</div>
<div class="flex-badge">ipsum dolor sit amet
<div class="hiddenIconTray">
<i class="icon">&</i>
</div>
</div>
<div class="flex-badge">Lorem ipsum dolor sit amet
<div class="hiddenIconTray">
<i class="icon">&</i>
</div>
</div>
<div class="flex-badge">Lorem
<div class="hiddenIconTray">
<i class="icon">&</i>
</div>
</div>
<div class="flex-badge">Lorem ipsum dolor sit amet
<div class="hiddenIconTray">
<i class="icon">&</i>
</div>
</div>
<div class="flex-badge">Lorem ipsum dolor sit amet
<div class="hiddenIconTray">
<i class="icon">&</i>
</div>
</div>
<div class="flex-badge">Lorem
<div class="hiddenIconTray">
<i class="icon">&</i>
</div>
</div>
<div class="flex-badge">ipsum dolor
<div class="hiddenIconTray">
<i class="icon">&</i>
</div>
</div>
<div class="flex-badge">Lorem
<div class="hiddenIconTray">
<i class="icon">&</i>
</div>
</div>
<div class="flex-badge">ipsum dolor
<div class="hiddenIconTray">
<i class="icon">&</i>
</div>
</div>
<div class="flex-badge">Lorem ipsum
<div class="hiddenIconTray">
<i class="icon">&</i>
</div>
</div>
<div class="flex-badge">Lorem ipsum dolor sit amet
<div class="hiddenIconTray">
<i class="icon">&</i>
</div>
</div>
<div class="flex-badge">ipsum dolor
<div class="hiddenIconTray">
<i class="icon">&</i>
</div>
</div>
<div class="flex-badge">Lorem ipsum dolor sit amet
<div class="hiddenIconTray">
<i class="icon">&</i>
</div>
</div>
</div>
I added resize: both
to the .flex-container
element in the example above so you can experiment with this and see that it works even as the parent element .flex-container
changes in size.
作者:黑洞官方问答小能手
链接:http://www.qianduanheidong.com/blog/article/516810/5020a334f7beb94d12fb/
来源:前端黑洞网
任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任
昵称:
评论内容:(最多支持255个字符)
---无人问津也好,技不如人也罢,你都要试着安静下来,去做自己该做的事,而不是让内心的烦躁、焦虑,坏掉你本来就不多的热情和定力
Copyright © 2018-2021 前端黑洞网 All Rights Reserved 版权所有,并保留所有权利。 京ICP备18063182号-3
投诉与举报,广告合作请联系vgs_info@163.com或QQ3083709327
免责声明:网站文章均由用户上传,仅供读者学习交流使用,禁止用做商业用途。若文章涉及色情,反动,侵权等违法信息,请向我们举报,一经核实我们会立即删除!