CSS 过渡不适用于 white-space:nowrap 和 text-overflow:悬停时省略号

CSS Transition not working with white-space: nowrap and text-overflow: ellipsis when hover

我在一些文本中设置了 white-space: nowraptext-overflow: ellipsis,当用户悬停时,它应该将 white-space 值更改为正常。悬停代码工作正常,但我无法使转换工作。

这是 CodePen link: https://codepen.io/anon/pen/qwYoyR

.App p {
  margin-bottom: 3px;
}
.App .bg-row {
  box-shadow: 0px 0px 5px #bdc3c7;
  background-color: #ecf0f1a3;
  padding: 20px;
  border-radius: 5px;
}
.App .bg-row .repositorios {
  transition: all 0.2s ease;
  margin-bottom: 20px;
}
.App .bg-row .repositorios:hover .repo-content {
  background-color: #d2d6d8;
  transition: 500ms ease-in-out;
}
.App .bg-row .repositorios .repo-image {
  width: 100%;
  height: auto;
  box-shadow: 0px 0px 5px #bdc3c7;
  -webkit-transition: all 0.2s ease;
  -moz-transition: all 0.2s ease;
  -o-transition: all 0.2s ease;
}
.App .bg-row .repositorios .repo-content {
  padding: 10px;
  transition: 500ms ease-in-out;
  overflow: hidden;
  box-shadow: 0px 0px 5px #bdc3c7;
  transition: 500ms ease-in-out;
  background-color: #ecf0f1;
}
.App .bg-row .repositorios .repo-content p {
  white-space: nowrap;
  text-overflow: ellipsis;
  overflow: hidden;
}
.App .bg-row .repositorios .repo-content .read-more {
  transition: 500ms ease-in-out;
  cursor: pointer;
}
.App .bg-row .repositorios .repo-content .read-more:hover {
  white-space: normal;
  transition: 500ms ease-in-out;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.3/css/bootstrap.min.css" rel="stylesheet"/>
<div class="container App">
  <div class="row bg-row">
    <div class="col-sm-6 col-md-4 col-lg-3 repositorios">
      <div class="repo-content">
        <p class="read-more">Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s</p>
      </div>
    </div>
  </div>
</div>

我认为您不能仅使用 css 来制作动画。要为高度设置动画,您需要明确设置它。我会尝试使用 js 获取真实高度,限制高度,然后在悬停时应用 js 中的高度。

CodePen example you can check

您需要固定 col-sm-6 col-md-4 col-lg-3 = "100%" 的宽度,这样您才能得到答案

<div class="container App">
    <div class="row bg-row">
      <div class="repositorios">
        <div class="repo-content">
          <p class="read-more">Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s</p>
      </div>
  </div>
</div>

应用这个CSS它会为你工作

.App {
  p {
    margin-bottom: 3px;
  }
  .bg-row {
    box-shadow: 0px 0px 5px #bdc3c7;
    background-color: #ecf0f1a3;
    padding: 20px;
    border-radius: 5px;
    .repositorios {
      transition: all 0.2s ease;
      margin-bottom: 20px;
      &:hover {
        .repo-content {
          background-color: #d2d6d8;
          transition: 500ms ease-in-out;
        }
      }
      .repo-image {
        width: 100%;
        height: auto;
        box-shadow: 0px 0px 5px #bdc3c7;
        -webkit-transition: all 0.2s ease;
        -moz-transition: all 0.2s ease;
        -o-transition: all 0.2s ease;
      }
      .repo-content {
        padding: 10px;
        transition: 500ms ease-in-out;
        overflow: hidden;
        box-shadow: 0px 0px 5px #bdc3c7;
        transition: 300ms ease-in-out;
        background-color: #ecf0f1;
        p {
          white-space: nowrap;
    text-overflow: ellipsis;
    overflow: hidden;
    width: 200px;
        }
        .read-more {
          transition: 500ms ease-in-out;
          cursor: pointer;
          &:hover {
            white-space: normal;
    transition: 300ms ease-in-out;
    width: 100%;
          }
        }
      }
    }
  }
}

或者你可以用 Jquery 来完成 codepen

$('.repo-content').hover(function(e){
  $(this).animate({height: '100%'}, 100);
  $('.bg-row.row').animate({height: '100%'}, 500);
},function(){
  $(this).animate({height: '50px'}, 500);
});
.App p {
  
  margin-bottom: 3px;
}
 .App .bg-row {
   transition: 500ms ease-in-out;
  box-shadow: 0px 0px 5px #bdc3c7;
  background-color: #ecf0f1 a3;
  padding: 20px;
   z-index:99;
   height:100px;
  border-radius: 5px;
}
 .App .bg-row .repositorios {
  transition: all 0.2s ease;
  margin-bottom: 20px;
}
 .App .bg-row .repositorios:hover .repo-content {
  background-color: #d2d6d8;
  transition: 500ms ease-in-out;
}
 .App .bg-row .repositorios .repo-image {
  width: 100%;
  height: auto;
  box-shadow: 0px 0px 5px #bdc3c7;
  -webkit-transition: all 0.2s ease;
  -moz-transition: all 0.2s ease;
  -o-transition: all 0.2s ease;
}
 .App .bg-row .repositorios .repo-content {
  padding: 10px;
  overflow: hidden;
   height:50px;
  box-shadow: 0px 0px 5px #bdc3c7;
  background-color: #ecf0f1;
}
 .App .bg-row .repositorios .repo-content p {
  text-overflow: ellipsis;
  overflow: hidden;
 
}
 .App .bg-row .repositorios .repo-content .read-more {
  transition: 500ms ease-in-out;
  cursor: pointer;
   z-index:99;
}
 .App .bg-row .repositorios .repo-content .read-more:hover {
  
  transition: 500ms ease-in-out;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.3/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="container App">
    <div class="row bg-row">
      <div class="col-sm-6 col-md-4 col-lg-3 repositorios">
        <div class="repo-content">
          <p class="read-more">Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s</p>
      </div>
</div>
</div>
  </div>

顺便说一句,我不知道 scss 所以我把你的 scss 转换成了 css,对此我深表歉意。

问题是因为 white-space 不是 可动画的 属性。您可以制作动画 max-height 属性 - 请参阅 updated codepen 和相关摘录:

 .read-more {
      transition: 500ms ease-in-out;
      cursor: pointer;
      max-height: 2em; /* added */
      &:hover {
        white-space: normal;
        max-height: 100vh; /* added */
        transition: 500ms ease-in-out;
      }
    }

但是当 hover 关闭时 ,return 动画将无法工作,因为 white-space: nowrap 毁了它。


这是一个 hacky 解决方案,它只使用 max-height 作为 transition 并且省略号由 伪元素处理 - 请参阅 codepen 和下面的代码片段:

.App p {
  margin-bottom: 3px;
}
.App .bg-row {
  box-shadow: 0px 0px 5px #bdc3c7;
  background-color: #ecf0f1a3;
  padding: 20px;
  border-radius: 5px;
}
.App .bg-row .repositorios {
  margin-bottom: 20px;
}
.App .bg-row .repositorios:hover .repo-content {
  background-color: #d2d6d8;
}
.App .bg-row .repositorios:hover .repo-content .read-more {
  transition: all 500ms ease-in-out;
  white-space: normal;
  max-height: 100vh;
}
.App .bg-row .repositorios:hover .repo-content .read-more:after {
  transition: all 0.5s linear;
  opacity: 0;
}
.App .bg-row .repositorios .repo-image {
  width: 100%;
  height: auto;
  box-shadow: 0px 0px 5px #bdc3c7;
}
.App .bg-row .repositorios .repo-content {
  padding: 10px;
  overflow: hidden;
  box-shadow: 0px 0px 5px #bdc3c7;
  background-color: #ecf0f1;
}
.App .bg-row .repositorios .repo-content p {
  overflow: hidden;
}
.App .bg-row .repositorios .repo-content .read-more {
  transition: all 500ms ease-in-out;
  text-align: justify;
  display: flex;
  cursor: pointer;
  max-height: 1.7em;
  /* added */
}
.App .bg-row .repositorios .repo-content .read-more:after {
  transition: all 0.5s linear;
  content: '...';
  opacity: 1;
}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.3/css/bootstrap.min.css">

<div class="container App">
    <div class="row bg-row">
      <div class="col-sm-6 col-md-4 col-lg-3 repositorios">
        <div class="repo-content">
          <p class="read-more">Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s</p>
      </div>
</div>
</div>
  </div>

这些不是可以转换的属性。

white-space: nowrap;
text-overflow: ellipsis;

为了从一个 属性 过渡到另一个,CSS 需要中间值。 从 nowrap 到 normal 没有中间值,因为没有中间值从 heright: 0 到 auto,或从 display: none 到 block。

使用 CSS 实现此目的的唯一方法是为您的元素使用最大高度,并在悬停时转换它。然而,white-space/ellipsis 本身将不得不去 => 将它们替换为与父元素具有相同 backgroundColor 的伪元素:

.x {
    position: relative;
    overflow: hidden;

    max-height: 20px;                /* set this to the height your first row would be */
    background-color: red;           /* you can change this, ofc */
    transition: max-height .5s;      /* the duration of the transition */
}
.x:after {
    content: '...';
    position: absolute;
    top: 0; right: 0;

    height: 1.5em;                   /* positioning it in line with the text - hacky */
    padding: 0 .2em;
    background-color: red;           /* keep the same as parent - it cannot be transparent unfortunately */

    opacity: 1;
    transition: opacity 0s .5s;      /* will delay the appearance of the '...' until the expanding transition has finished */
}
.x:hover {
    max-height: 1000px;              /* can be lower to create smoother response time */
}
.x:hover::after {
    opacity: 0;
    transition: opacity 0s 0s;       /* will apply the appearance of the '...' when hovered */
}

Hacky,可改进,但只使用 CSS。

这可以通过 height: auto 实现,但是 CSS transition 需要高度固定值。但是您可以使用 jQuery 来解决这个问题。我只是写了一个基本的 mouseentermouseleave 方法和一些逻辑来获取内容 expand/collapse 高度。所有提到的更改都应用于以下代码,您还可以查看工作 fiddle。我希望它能帮助你。谢谢

Working Fiddle Example - https://jsfiddle.net/creative_sid5/bgpus3q6/42/

var rm = $('.read-more');   
var rmInitialHeight = 0;
var rmExpandedHeight = rm.outerHeight() + 'px';
rm.removeClass('active');
setTimeout(function(){
  rmInitialHeight = rm.outerHeight() + 'px';
  rm.height(rmInitialHeight);
}, 500)
rm.mouseenter(function() {       
  toggle(rmExpandedHeight);
});
rm.mouseleave(function() {       
  toggle(rmInitialHeight);
})  

function toggle(h) {
  rm.toggleClass('active').css('height', h);
}
.App p {
  margin-bottom: 3px; }

.App .bg-row {
  box-shadow: 0px 0px 5px #bdc3c7;
  background-color: #ecf0f1a3;
  padding: 20px;
  border-radius: 5px; }
  .App .bg-row .repositorios {
    transition: all 0.2s ease;
    margin-bottom: 20px; }
    .App .bg-row .repositorios:hover .repo-content {
      background-color: #d2d6d8;
      transition: 500ms ease-in-out; }
    .App .bg-row .repositorios .repo-image {
      width: 100%;
      height: auto;
      box-shadow: 0px 0px 5px #bdc3c7;
      -webkit-transition: all 0.2s ease;
      -moz-transition: all 0.2s ease;
      -o-transition: all 0.2s ease; }
    .App .bg-row .repositorios .repo-content {
      padding: 10px;
      transition: 500ms ease-in-out;
      overflow: hidden;
      box-shadow: 0px 0px 5px #bdc3c7;
      transition: 500ms ease-in-out;
      background-color: #ecf0f1; }
      .App .bg-row .repositorios .repo-content .read-more {
        transition: 500ms ease-in-out;
        cursor: pointer;
        white-space: nowrap;
        text-overflow: ellipsis;
        overflow: hidden; }
      .App .bg-row .repositorios .repo-content .active {
        white-space: normal; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">

<div class="container App">
  <div class="row bg-row">
    <div class="col-sm-6 col-md-4 col-lg-3 repositorios">
      <div class="repo-content">
        <p class="read-more active">Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s</p>
      </div>
    </div>
  </div>
</div>

我这里有一个使用 React 和 CSS 的示例,但您可以在纯 JS 或您选择的框架中实现相同的目的。 这里的关键是测量元素的展开(隐藏,克隆)高度和折叠高度,然后通过 CSS transition.

处理动画。
import React, { useState } from "react";

const ShowMore = ({ text }) => {
  const [isOpen, toggle] = useState(false);
  const [
    isOnGoingCollapseTransition,
    setisOnGoingCollapseTransition
  ] = useState(false);
  const [initialHeight, setInitialHeight] = useState(0);
  const ref = React.useRef();
  const measureRef = React.useRef();
  React.useLayoutEffect(() => {
    setInitialHeight(ref.current.getBoundingClientRect().height);
  }, []);
  const onTransitionEnd = () => {
    if (isOpen) {
      setisOnGoingCollapseTransition(true);
    } else {
      setisOnGoingCollapseTransition(false);
    }
  };
  return (
    <div className="relative">
      <div className="absolute hidden" ref={measureRef}>
        {text}
      </div>
      <div
        onTransitionEnd={onTransitionEnd}
        className="overflow-hidden transition"
        style={{
          height: isOpen
            ? measureRef.current.getBoundingClientRect().height
            : initialHeight
        }}
      >
        <div
          ref={ref}
          className={
            !isOpen && !isOnGoingCollapseTransition ? "overflow-ellipsis" : ""
          }
        >
          {text}
        </div>
      </div>
      <span className="text-blue" onClick={() => toggle(open => !open)}>
        {isOpen ? <span>show less</span> : <span>show more</span>}
      </span>
    </div>
  );
};

export default ShowMore;

CSS:

    .relative{
      position: relative;
    }
    .absolute{
      position: absolute;
    }
    .overflow-ellipsis{
      white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
    }
    .overflow-hidden{
      overflow: hidden;
    }
    .text-blue{
      color: blue;
      cursor: pointer;
    }
    .transition{
      transition: 225ms height linear;
    }
    .hidden{
      transform: translate(1000px);
    }

检查这个工作示例 Ellipsis collapse transition