【问题标题】:In pure CSS, is it possible to set margin equal to height of current element?在纯 CSS 中,是否可以将边距设置为等于当前元素的高度?
【发布时间】:2014-09-12 12:39:50
【问题描述】:

我有一个垂直的项目堆栈,用户可以通过单击一个按钮来附加一个项目,大致如下。

<ol>
  <li><textarea></textarea></li>
  <li><textarea></textarea></li>
</ol>
<a data-action="additem">Add another</a>

我正在尝试编写一个 CSS 动画,以便在插入新的 li 时,“添加另一个”平滑地滑到它的新位置。 li 标签上的固定高度不是一个选项,我试图避免使用 max-height 动画技巧,因为它可能会产生奇怪的布局效果。

我发现我可以将 margin-bottomsomething 动画到 0 并获得所需的效果,但我不知道如何在 CSS 中表达我想要的当前高度应用此规则的元素。百分比是相对于元素的 width 测量的,这不是我在这里需要的,我想不出一个巧妙的技巧使用calc 或类似的东西来表达我想要的浏览器。

建议?

编辑

我正在使用带有重复绑定的模板将项目添加到列表中。 JS 仅将另一个对象推入可观察数组,框架处理实际的 DOM 插入。 li 标签上有以下 CSS 以使其顺利进入:

animation: append forwards .5s;

append定义为:

@keyframes append {
    from {
        transform: translateX(10%);
        opacity: 0;
        margin-bottom: _____;
    }

    to {
        transform: none;
        opacity: 1;
        margin-bottom: 0;
    }
}

【问题讨论】:

标签: html css css-animations


【解决方案1】:

目前没有...

我多次遇到这个令人沮丧的问题,总是尝试为非数字值设置动画,将当前元素的特定属性作为动画值访问,或者将未指定的值设置为指定的值.一般来说,我总是不得不退回到某种形式的不太完美的max-height 动画(就像你已经提到的那样),或者使用 CSS 和 JavaScript/jQuery 的混合体。

对于您的问题,有几个选项,但没有一个是您真正想要的。


仅 css 版本(使用重复的标记和另一个动画)

在纯 CSS hack 中经常使用的一个技巧是复制标记(在本例中为链接本身)并将其放置在将通过不同方式打开或关闭的父包装器中。这种方法的缺点是你会得到一个相当难看的标记,在这个特定的例子中,一个项目符号编号看起来很刺耳(因为必须将不透明动画从 li 移动到 textarea)。

然而,这种方法的好处是,通过移动 li 内的链接,您可以在 y 轴上使用带有平移或其他偏移方法的 -100%。奇怪的是,虽然我无法计算出translateY(-100%) 的计算依据... 它似乎不是父高度,也许它是它自身的高度。出于这个原因,我更新了小提琴以使用 bottom 和相对定位,尽管在 Firefox(在 Mac 上)这会短暂出现故障。

translateY 似乎是根据自己的高度计算百分比,所以为了解决这个问题,我不得不使用绝对位置并强制链接层采用相同的尺寸因为 li... 很烦人,因为它涉及对链接上方的 textarea 进行 z 索引,并使用内部 span 来偏移链接文本,但至少它确实有效。

以下代码适用于最新的 Firefox,如果正确使用所有不同的浏览器前缀来定义动画关键帧,也适用于其他现代浏览器,但是我现在没有时间设置它们。

标记:

<ol class="list">
  <li><textarea></textarea><a class="add" href="#"><span>Add another</span></a></li>
  <li><textarea></textarea><a class="add" href="#"><span>Add another</span></a></li>
</ol>

css:

ol li {
  position: relative;
}
ol li .add {
  display: none;
}
ol li:last-child .add {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  top: 0;
  width: 100%;
  height: 100%;
  display: block;
  animation-duration: 1s;
  animation-name: slide;
}

ol li:last-child .add span {
    position: absolute;
    bottom: -20px;
}

.list li textarea {
  position: relative;
  animation-duration: 1s;
  animation-name: append;
  z-index: 1;
}

@keyframes append {
  from {
    transform: translateX(10%);
    opacity: 0;
  }
  to {
    transform: none;
    opacity: 1;
  }
}

@keyframes slide {
  from {
    transform: translateY(-100%);
  }
  to {
    transform: none;
  }
}


javascript 版本(代码触发翻译)

http://jsfiddle.net/7m8F9/1/

以下显然没有考虑到您正在使用模板引擎来支持您的 DOM 操作这一事实,但所有代码需要正常工作是列表的前后高度(计算height),以及在添加新列表项时触发的事件。

遗憾的是,目前还不可能在纯 CSS 中完成这一切,至少在我所见的情况下,也许一旦 calc 升级了......?或者,如果引入了某种方式来引用当前元素的尺寸,而不仅仅是它的偏移父级。

应该注意的是,我没有 Internet Explorer 来测试它,但所有其他现代浏览器似乎都很满意。

标记:

<ol class="list">
  <li><textarea></textarea></li>
  <li><textarea></textarea></li>
</ol>
<div class="add">
  <a href="#">Add another</a>
</div>

javascript(带有 jQ​​uery):

function prefix(){
  for ( var a = ['Webkit','Moz','O','ms'], i=0, l = a.length; i<l; i++ ) {
    if ( document.body.style[a[i]+'AnimationName'] !== undefined ) {
      return { js: a[i], css: '-' + a[i].toLowerCase() + '-' };
    }
  }
  return { css:'', js:'' };
}

$(function(){
  $('.add a').click(function(e){
    e.preventDefault();
    var pref = prefix(),
      link = $(this).parent(), 
      list = $('.list'),
      lihi = list.height(),
      liad = $('<li><textarea></textarea></li>').appendTo(list),
      lihd = lihi - list.height();
      link.css(pref.css + 'transform', 'translateY(' + lihd + 'px)');
    setTimeout(function(){link.addClass('translate-zero transition-all');},0);
    setTimeout(function(){
      link.css(pref.css + 'transform', '');
      link.removeClass('translate-zero transition-all');
    },500);
  });
});

css:

.transition-all {
  -webkit-transition: all 0.5s;
  -moz-transition: all 0.5s;
  -ms-transition: all 0.5s;
  -o-transition: all 0.5s;
  transition: all 0.5s;
}

.translate-zero {
  -webkit-transform: translateY(0) !important;
  -moz-transform: translateY(0) !important;
  -ms-transform: translateY(0) !important;
  -o-transform: translateY(0) !important;
  transform: translateY(0) !important;
}

.list li {
  animation-duration: 1s;
  animation-name: append;
}

@keyframes append {
  from {
    transform: translateX(10%);
    opacity: 0;
  }
  to {
    transform: none;
    opacity: 1;
  }
}


重新设计版本

我多次遇到类似问题,只是发现重新设计有助于消除问题,并且通常可以实际提高可用性。在您的情况下,最好将“添加链接”放在列表上方(或右上角),或者将按钮作为浮动图标集成到某处......无论您放在哪里,最好尝试保留它在静态位置,移动交互点可能会让用户感到厌烦,尤其是当他们希望快速连续添加多个项目时。

【讨论】:

  • 我已经在考虑的一个问题是如何在 DOM 中的上下文之间为元素设置动画;这个想法类似于 IE 和 Chrome 如何将标签关闭按钮保留在鼠标下方,直到您离开。我怀疑这也是不可能的。
【解决方案2】:

我能想到的最简单的解决方案就是这个。

当你添加一个新的 li 元素时,只需将它附加到 dom 中即可。

liMarkup = '<li><textarea></textarea></li>'
$('ol').append(liMarkup);
$('ol').find('li').last().css('display','none');
$('ol').find('li').last().show('fast');

这将根据您的要求工作 :) 我希望它有所帮助。

工作Jsfiddle

编辑:在 JS 中更容易更好地做到这一点。

【讨论】:

  • 您的编辑未经证实。首先这不是JS,是jQuery(不是每个人都会/可以使用jQuery),其次为什么更好?
猜你喜欢
  • 2011-08-30
  • 2021-11-18
  • 1970-01-01
  • 1970-01-01
  • 2016-01-14
  • 1970-01-01
  • 2011-12-03
  • 2014-02-15
  • 2012-06-23
相关资源
最近更新 更多