繁体   English   中英

在 flex 行包装容器中扩展 hover 上的 div 会导致子元素的移动

[英]Expanding div on hover in a flex row wrap container causes shifting of children elements

我正在编写一些 css/html 元素并遇到了这个问题。 一直在搜索 web 寻找潜在的解决方案,但似乎没有一个能解决我的问题。

我有动态数量的子元素需要适合父元素(弹性容器)进行显示。 子元素有点像徽章,您可以在其中显示信息。 在 hover 上,子元素应展开宽度过渡并显示一个实用程序图标供我单击。 到目前为止一切都很好。 问题是在悬停时,因为孩子会展开,如果它是 flex 中行的“最后一个”孩子,它将移动到下一行并完全展开,我再也无法到达图标。

有什么解决办法吗? 我尝试对孩子施加负边距以欺骗它留在它所在的同一行,但孩子本身的整个身体在溢出时被父容器切断(它看起来也不是很好)。

我还尝试强制每行仅 n 个子元素(例如每行 2 个子元素),但这只会降低问题发生的机会,并不能有效地消除它。

我希望寻找的是保持宽度过渡并允许动态数量的子元素填充到父容器元素中并在每行填充尽可能多的子元素(因此是 flex 行换行),同时所有子元素都被刷新到左边。

演示(下)中的“&”是图标; 注意在 hover 上无法到达某些行末尾的某些子元素,因为它们会进入下一行。

 .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"> &nbsp; <i class="icon">&</i> </div> </div> <div class="flex-badge">Lorem <div class="hiddenIconTray"> &nbsp; <i class="icon">&</i> </div> </div> <div class="flex-badge">Lorem <div class="hiddenIconTray"> &nbsp; <i class="icon">&</i> </div> </div> <div class="flex-badge">Lorem <div class="hiddenIconTray"> &nbsp; <i class="icon">&</i> </div> </div> <div class="flex-badge">Lorem <div class="hiddenIconTray"> &nbsp; <i class="icon">&</i> </div> </div> <div class="flex-badge">ipsum dolor sit <div class="hiddenIconTray"> &nbsp; <i class="icon">&</i> </div> </div> <div class="flex-badge">Lorem ipsum dolor sit amet <div class="hiddenIconTray"> &nbsp; <i class="icon">&</i> </div> </div> <div class="flex-badge">ipsum dolor sit amet <div class="hiddenIconTray"> &nbsp; <i class="icon">&</i> </div> </div> <div class="flex-badge">Lorem ipsum dolor sit amet <div class="hiddenIconTray"> &nbsp; <i class="icon">&</i> </div> </div> <div class="flex-badge">Lorem <div class="hiddenIconTray"> &nbsp; <i class="icon">&</i> </div> </div> <div class="flex-badge">Lorem ipsum dolor sit amet <div class="hiddenIconTray"> &nbsp; <i class="icon">&</i> </div> </div> <div class="flex-badge">Lorem ipsum dolor sit amet <div class="hiddenIconTray"> &nbsp; <i class="icon">&</i> </div> </div> <div class="flex-badge">Lorem <div class="hiddenIconTray"> &nbsp; <i class="icon">&</i> </div> </div> <div class="flex-badge">ipsum dolor <div class="hiddenIconTray"> &nbsp; <i class="icon">&</i> </div> </div> <div class="flex-badge">Lorem <div class="hiddenIconTray"> &nbsp; <i class="icon">&</i> </div> </div> <div class="flex-badge">ipsum dolor <div class="hiddenIconTray"> &nbsp; <i class="icon">&</i> </div> </div> <div class="flex-badge">Lorem ipsum <div class="hiddenIconTray"> &nbsp; <i class="icon">&</i> </div> </div> <div class="flex-badge">Lorem ipsum dolor sit amet <div class="hiddenIconTray"> &nbsp; <i class="icon">&</i> </div> </div> <div class="flex-badge">ipsum dolor <div class="hiddenIconTray"> &nbsp; <i class="icon">&</i> </div> </div> <div class="flex-badge">Lorem ipsum dolor sit amet <div class="hiddenIconTray"> &nbsp; <i class="icon">&</i> </div> </div> </div>

谢谢!

您可以在这种情况下使用的一种巧妙的解决方法是在您需要之前分配您想要使用的间距量。

这里需要几个步骤……

  • 我们知道这些flex-badge元素在展开后可能会换行到下一行,因此我们可以预期可能会添加一个我们知道宽度将增加的确切大小的margin-right值,您将其设置为20px 因为您已经设置了一些边距来分隔这些 flex 元素,所以我将您的原始边距移动到父级上设置的gap属性,这是该属性的预期用途。 所有现代浏览器都正式支持这一点( caniuse.com )。
  • 为了改变这个margin ,我们还必须考虑这样一个事实,即向所有flex-badge元素添加margin-right: 20px会在每个元素之间添加一个不需要的间隙。 我们还可以通过在所有flex-badge元素上预先添加margin-left: -20px来抵消这种副作用。
  • 在 hover 上,我们希望将悬停元素上的这个margin-right值转换为0 ,以随着元素的hiddenIconTray子元素填充的空间增加以填充空白而流畅地减少预分配的空间。
  • 由于这也会导致其行中的第一个元素也从父容器的左侧流血,因此我们将其与应用于父元素的padding-left: 20px配对。

就是这样,一个功能齐全的容器,其中元素提前换行到下一行。 如果他们会在悬停时这样做。 瞧✨

 .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"> &nbsp; <i class="icon">&</i> </div> </div> <div class="flex-badge">Lorem <div class="hiddenIconTray"> &nbsp; <i class="icon">&</i> </div> </div> <div class="flex-badge">Lorem <div class="hiddenIconTray"> &nbsp; <i class="icon">&</i> </div> </div> <div class="flex-badge">Lorem <div class="hiddenIconTray"> &nbsp; <i class="icon">&</i> </div> </div> <div class="flex-badge">Lorem <div class="hiddenIconTray"> &nbsp; <i class="icon">&</i> </div> </div> <div class="flex-badge">ipsum dolor sit <div class="hiddenIconTray"> &nbsp; <i class="icon">&</i> </div> </div> <div class="flex-badge">Lorem ipsum dolor sit amet <div class="hiddenIconTray"> &nbsp; <i class="icon">&</i> </div> </div> <div class="flex-badge">ipsum dolor sit amet <div class="hiddenIconTray"> &nbsp; <i class="icon">&</i> </div> </div> <div class="flex-badge">Lorem ipsum dolor sit amet <div class="hiddenIconTray"> &nbsp; <i class="icon">&</i> </div> </div> <div class="flex-badge">Lorem <div class="hiddenIconTray"> &nbsp; <i class="icon">&</i> </div> </div> <div class="flex-badge">Lorem ipsum dolor sit amet <div class="hiddenIconTray"> &nbsp; <i class="icon">&</i> </div> </div> <div class="flex-badge">Lorem ipsum dolor sit amet <div class="hiddenIconTray"> &nbsp; <i class="icon">&</i> </div> </div> <div class="flex-badge">Lorem <div class="hiddenIconTray"> &nbsp; <i class="icon">&</i> </div> </div> <div class="flex-badge">ipsum dolor <div class="hiddenIconTray"> &nbsp; <i class="icon">&</i> </div> </div> <div class="flex-badge">Lorem <div class="hiddenIconTray"> &nbsp; <i class="icon">&</i> </div> </div> <div class="flex-badge">ipsum dolor <div class="hiddenIconTray"> &nbsp; <i class="icon">&</i> </div> </div> <div class="flex-badge">Lorem ipsum <div class="hiddenIconTray"> &nbsp; <i class="icon">&</i> </div> </div> <div class="flex-badge">Lorem ipsum dolor sit amet <div class="hiddenIconTray"> &nbsp; <i class="icon">&</i> </div> </div> <div class="flex-badge">ipsum dolor <div class="hiddenIconTray"> &nbsp; <i class="icon">&</i> </div> </div> <div class="flex-badge">Lorem ipsum dolor sit amet <div class="hiddenIconTray"> &nbsp; <i class="icon">&</i> </div> </div> </div>

最后一点仍然需要更多关注。 这些项目现在相互重叠,而不是随着它们的增长和收缩而相互推拉。 不幸的是,仅使用 CSS 是无法避免的,因为这是我们执行的边距调整的结果。

但是,如果您愿意使用一点 JavaScript,我们可以借助一个简单的循环来完美地工作,将 class 添加到每个 flex 行中的第一个元素,这样我们就可以样式识别这些并应用基于 flex 的 ZBC4150D023D3255F236DB67 -rows 而不是弹性项目。 这是 CSS 中尚不支持的功能,但希望在接下来的行中,我们将获得用于 flex 和 grid 行和列的伪类。 这与即将推出的:has()伪选择器配对,仅使用 CSS 即可实现。

我们还可以使用所有现代浏览器都支持的内置 ResizeObserver API ( caniuse.com )。

这是在行动:

 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"> &nbsp; <i class="icon">&</i> </div> </div> <div class="flex-badge">Lorem <div class="hiddenIconTray"> &nbsp; <i class="icon">&</i> </div> </div> <div class="flex-badge">Lorem <div class="hiddenIconTray"> &nbsp; <i class="icon">&</i> </div> </div> <div class="flex-badge">Lorem <div class="hiddenIconTray"> &nbsp; <i class="icon">&</i> </div> </div> <div class="flex-badge">Lorem <div class="hiddenIconTray"> &nbsp; <i class="icon">&</i> </div> </div> <div class="flex-badge">ipsum dolor sit <div class="hiddenIconTray"> &nbsp; <i class="icon">&</i> </div> </div> <div class="flex-badge">Lorem ipsum dolor sit amet <div class="hiddenIconTray"> &nbsp; <i class="icon">&</i> </div> </div> <div class="flex-badge">ipsum dolor sit amet <div class="hiddenIconTray"> &nbsp; <i class="icon">&</i> </div> </div> <div class="flex-badge">Lorem ipsum dolor sit amet <div class="hiddenIconTray"> &nbsp; <i class="icon">&</i> </div> </div> <div class="flex-badge">Lorem <div class="hiddenIconTray"> &nbsp; <i class="icon">&</i> </div> </div> <div class="flex-badge">Lorem ipsum dolor sit amet <div class="hiddenIconTray"> &nbsp; <i class="icon">&</i> </div> </div> <div class="flex-badge">Lorem ipsum dolor sit amet <div class="hiddenIconTray"> &nbsp; <i class="icon">&</i> </div> </div> <div class="flex-badge">Lorem <div class="hiddenIconTray"> &nbsp; <i class="icon">&</i> </div> </div> <div class="flex-badge">ipsum dolor <div class="hiddenIconTray"> &nbsp; <i class="icon">&</i> </div> </div> <div class="flex-badge">Lorem <div class="hiddenIconTray"> &nbsp; <i class="icon">&</i> </div> </div> <div class="flex-badge">ipsum dolor <div class="hiddenIconTray"> &nbsp; <i class="icon">&</i> </div> </div> <div class="flex-badge">Lorem ipsum <div class="hiddenIconTray"> &nbsp; <i class="icon">&</i> </div> </div> <div class="flex-badge">Lorem ipsum dolor sit amet <div class="hiddenIconTray"> &nbsp; <i class="icon">&</i> </div> </div> <div class="flex-badge">ipsum dolor <div class="hiddenIconTray"> &nbsp; <i class="icon">&</i> </div> </div> <div class="flex-badge">Lorem ipsum dolor sit amet <div class="hiddenIconTray"> &nbsp; <i class="icon">&</i> </div> </div> </div>

我在上面示例中的.flex-container元素中添加了resize: both ,因此您可以对此进行试验,并看到它即使在父元素.flex-container大小发生变化时也能正常工作。

由于您指定了<div class="flex-container">的宽度:40vw,因此该 div 的子元素将尝试适应指定的 40vw 区域。

我建议你设置min-width: 40vwmax-width: 50vw这样当你对子元素进行 hover 时,父 div 将拉伸到 50vw。

祝你好运!

这是正常的 flex 行为,如果元素太大,它会向下流动。 您这样做的唯一方法是节省图标出现的空间。

https://jsfiddle.net/rm9j8cb3/2/

检查它是如何完成的。 您在徽章元素上有 padding-right,它通过::before元素覆盖以“隐藏它”,因此它看起来像空白。 然后,当悬停徽章时,图标从左侧出现在该::before元素上方并显示自身。 如果项目应该太大,它就会掉下来。

我希望这对你有用。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM