如何选择最后一行文字的第一个单词? (<h1> - </h1> <h6>,<p>元素)

时间:2017-07-13 09:37:28

标签: javascript jquery css

我需要在我正在构建的网站上的每个h1-h6元素下添加一条水平线。我目前正在添加一个after元素:

h1, h2, h3, h4, h5, h6 {
  text-transform: uppercase;
  color: #000;
  margin-top: 0;
  margin-bottom: 2rem;
  font-weight: 800;
  color: #333;
  display: inline-block;
  position: relative;
  text-rendering: optimizeLegibility;
  font-family: $altfont;
  position: relative;
  &:after {
    content: '';
    position: absolute;
    bottom:0;
    left:0;
    width: 60px;
    height: 4px;
    background-color: $yellow;
  }
}

我还有一个小的jQuery函数,以确保after元素总是低于元素20px:

$(function () {
    $('h1, h2, h3, h4, h5, h6').each(function () {

            x = parseInt($(this).css('font-size'));
            $(this).css('line-height', (x + 20) + 'px');

    });
});

如果h1左侧有文本对齐,则此方法有效 - 当文本换行为2行或更多行时,after元素将显示在最后一行的第一个单词下。

问题是,如果文本居中对齐或右对齐,则after元素将显示在h1元素下,但不会显示在最后一行的第一个字下。这是可以用JS / JQuery完成的吗?

以下是所发生情况的图片。在第二个例子中,我希望黄色线显示在“Slice”一词下面。

enter image description here

6 个答案:

答案 0 :(得分:1)

修改

这是一个很好的挑战! 它需要4个循环来实现你的要求。

  1. 在每个单词上添加span
  2. 查找最后一行span的偏移量。
  3. 删除除最后一行以外的所有行的跨度。
  4. 删除除第一个以外的所有字词的跨度。
  5. CodePen

    请参阅代码中的注释(我保留了所有调试console.logs)

    &#13;
    &#13;
    $(function () {
      $('h1, h2, h3, h4, h5, h6').each(function () {
    
        x = parseInt($(this).css('font-size'));
        $(this).css('line-height', (x + 20) + 'px');
    
        findWord($(this));
    
      });
    
      function findWord(el){
    
        // Get the word array.
        var wordArr = el.html().split(" ");
    
        // Cycle words to add span on each words.
        for(i=0;i<wordArr.length;i++){
          console.log(wordArr[i]);
          wordArr[i] = "<span class='underliner'>"+wordArr[i]+"</span>";
        }
    
        // Update HTML.
        el.html(wordArr.join(" "));
    
        // Find the offset of the last line.
        var biggestOffset=0;
        el.find(".underliner").each(function(){
          console.log($(this).offset().top);
          if($(this).offset().top>biggestOffset){
            biggestOffset=$(this).offset().top;
          }
        });
    
        console.log("biggestOffset: "+biggestOffset);
    
        // Remove span on NOT the last line
        el.find(".underliner").each(function(){
          if($(this).offset().top<biggestOffset){
            $(this).replaceWith($(this).html());
          }
        });
    
        // On the last line, remove all spans except on the first word
        el.find(".underliner").not(":eq(0)").each(function(){
          $(this).replaceWith($(this).html());
        });
      }
    });
    &#13;
    h1, h2, h3, h4, h5, h6 {
      text-transform: uppercase;
      color: #000;
      margin-top: 0;
      margin-bottom: 2rem;
      font-weight: 800;
      /*color: #333;*/
      display: inline-block;
      position: relative;
      text-rendering: optimizeLegibility;
      font-family: $altfont;
      position: relative;
      
      text-align:center;  /* ADDED */
      
      /* REMOVED */
      /*&:after {
        content: '';
        position: absolute;
        bottom:0;
        left:0;
        width: 60px;
        height: 4px;
        background-color: &yellow;
      }*/
    }
    
    .underliner{
      text-decoration:underline;
      text-decoration-color: red
    }
    &#13;
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    
    <h1>This is a quite long H1 that will certainly wrap</h1>
    <h2>This is a quite long H2 that will certainly wrap</h2>
    <h3>This is a quite long H3 that will certainly wrap</h3>
    <h4>This is a quite long H4 that will certainly wrap</h4>
    <h5>This is a quite long H5 that will certainly wrap</h5>
    <h6>This is a quite long H6 that will certainly wrap</h6>
    &#13;
    &#13;
    &#13;



    <小时/> 第一个答案
    (误读了问题......)


    因为你已经使用了jQuery ...

    您可以将$(this).append($("<div class='smallBar'>").css({"top":x+10}))添加到脚本中...
    并使用CSS来定义smallBar,方法与after伪元素相同。

    CodePen

    &#13;
    &#13;
    $(function () {
      $('h1, h2, h3, h4, h5, h6').each(function () {
    
        x = parseInt($(this).css('font-size'));
        $(this).css('line-height', (x + 20) + 'px');
        $(this).append($("<div class='smallBar'>").css({"top":x+10}))
    
      });
    });
    &#13;
    h1, h2, h3, h4, h5, h6 {
      text-transform: uppercase;
      color: #000;
      margin-top: 0;
      margin-bottom: 2rem;
      font-weight: 800;
      /*color: #333;*/
      display: inline-block;
      position: relative;
      text-rendering: optimizeLegibility;
      font-family: $altfont;
      position: relative;
      /*&:after {
        content: '';
        position: absolute;
        bottom:0;
        left:0;
        width: 60px;
        height: 4px;
        background-color: &yellow;
      }*/
    }
    .smallBar{
      position: absolute;
        top:0;
        left:0;
        width: 60px;
        height: 4px;
        background-color: red;
    }
    &#13;
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <h1>This is a quite long H1 that will certainly wrap</h1>
    <h2>This is a quite long H2 that will certainly wrap</h2>
    <h3>This is a quite long H3 that will certainly wrap</h3>
    <h4>This is a quite long H4 that will certainly wrap</h4>
    <h5>This is a quite long H5 that will certainly wrap</h5>
    <h6>This is a quite long H6 that will certainly wrap</h6>
    &#13;
    &#13;
    &#13;

答案 1 :(得分:1)

我找到并突出显示最后一行第一个单词的算法:

  1. 迭代元素。
  2. 获取元素的文本(innerText)。
  3. 按空格(“”)符号分割文字。
  4. 从块中删除所有元素。
  5. 使用单词和空白文本节点添加span s(同时将此span保存到数组中。)
  6. span排序此数组,top的{​​{1}}矩形left最低span
  7. 将突出显示类添加到此数组的顶部元素。
  8. highlightFirstWordOfLastLineForHeaders();
    
    /* apply highlighting on window resize */
    window.addEventListener("resize", highlightFirstWordOfLastLineForHeaders);
    
    /* Peforms highlightFirstWordOfLastLine call for every header element */
    function highlightFirstWordOfLastLineForHeaders() {
      var elements = document.querySelectorAll("h1, h2, h3, h4, h5, h6");
    
      for (var i = 0; i < elements.length; i++) {
        highlightFirstWordOfLastLine(elements[i]);
      }
    }
    
    /* Peforms highlighting for single element */
    function highlightFirstWordOfLastLine(element) {
      var text = element.innerText.trim();
    
      /* get words list */
      var words = text.split(" ");
    
      /* removing all elements */
      while (element.firstChild) {
        element.removeChild(element.firstChild);
      }
    
      var spanArray = [];
    
      /* add spans with words and whitespaces */
      for (var i = 0; i < words.length; i++) {
        /* append span with word */
        var span = document.createElement("span");
        span.appendChild(document.createTextNode(words[i]));
        element.appendChild(span);
        /* append whitespace */
        element.appendChild(document.createTextNode(" "));
        /* save span element to array */
        spanArray.push(span);
      }
    
      /* sorting by highest top and lowest left */
      spanArray.sort(function(a, b) {
        var rectA = a.getBoundingClientRect();
        var rectB = b.getBoundingClientRect();
    
        var deltaTop = rectB.top - rectA.top;
    
        /* if differense is less then 1px */
        if (Math.abs(deltaTop) < 1) {
          return rectA.left - rectB.left;
        }
    
        return deltaTop;
      });
    
      /* appending highlighting to fist word of last line */
      spanArray[0].classList.add("selected");
    }
    .selected {
      border-bottom: 2px solid yellow;
    }
    <h1>
      Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent ultrices porta nibh, eu semper massa ullamcorper et.
    </h1>
    
    <h2>
      Curabitur in venenatis sapien. Nullam cursus ante ac enim dapibus, a egestas tellus mollis.
    </h2>
    
    <h3>
      Aenean tincidunt ligula et egestas suscipit. Proin euismod felis leo, egestas porta purus porta vitae. Morbi ut pulvinar quam, eu accumsan eros. Duis tristique pretium imperdiet. Integer nunc odio, consectetur vel leo vel, posuere venenatis nunc. Vestibulum sit amet arcu sit amet tortor faucibus maximus in id massa. Praesent vulputate, tellus nec aliquam tempor, ipsum erat tincidunt est, sit amet cursus turpis dui ac ipsum. Duis nec odio in felis aliquet sagittis sit amet in leo. Suspendisse potenti. Curabitur vitae sagittis diam. Duis id lectus cursus purus ultricies sollicitudin. Phasellus a ex sit amet eros lacinia fringilla sit amet sit amet sem. Proin luctus ornare risus at volutpat. Aliquam eleifend porttitor nulla. Sed facilisis mattis felis ut sodales.
    </h3>
    
    <h4>
      Quisque quis ultricies arcu. Aliquam feugiat non ipsum quis malesuada. Suspendisse ullamcorper, eros ut maximus hendrerit, sem velit lobortis turpis, non tristique justo magna eu nulla. Vestibulum maximus auctor ipsum sit amet finibus. Etiam commodo iaculis sem, vitae tincidunt libero. Phasellus lacus quam, semper ut pulvinar sed, accumsan a arcu. Suspendisse nulla velit, rhoncus id porttitor at, dictum ac ante. Sed eleifend vitae quam eget pretium.
    </h4>
    
    <h5>
      Duis semper rhoncus ultrices. Aliquam id elit nec quam fringilla gravida ac sed nisi. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec lorem leo, rhoncus quis nulla eget, posuere pellentesque leo. Nam in nisi sit amet sem consequat sodales. Quisque leo urna, aliquet eu malesuada at, laoreet et lorem. Fusce est neque, fringilla id ex id, semper tincidunt mauris. Aliquam erat volutpat. Vestibulum sodales sodales tincidunt. Pellentesque elementum quis neque vel malesuada. Nulla non scelerisque enim, ut posuere tortor. Fusce vel neque tristique ipsum aliquet mattis at sed sapien.
    </h5>
    
    <h6>
      Praesent scelerisque magna libero, vitae commodo purus tincidunt in. Etiam placerat diam turpis, sit amet iaculis eros efficitur at. Sed porta, dui non condimentum vestibulum, libero enim cursus nibh, eu luctus ligula ante sed neque. Duis vestibulum lacus felis, at iaculis tellus malesuada at. Donec vehicula lacinia metus. Pellentesque non efficitur lectus. Etiam et consectetur massa. Proin et leo cursus, convallis diam sit amet, mattis arcu. Fusce posuere pharetra leo eget volutpat. Maecenas et posuere urna. Nullam a dolor eu ipsum placerat rhoncus. In cursus, mauris ut pulvinar pellentesque, diam orci facilisis ante, at sollicitudin libero turpis in libero. In maximus est eu nisl venenatis ultrices.
    </h6>

    您还可以通过jsFiddle了解窗口大小调整的工作原理。

答案 2 :(得分:0)

虽然未经测试,但这种逻辑是有道理的。

编写一些查看h1大小的JS,如果h1的大小大于X,那么h1的大小可能会稍微增加到最佳状态。

然后将样式添加到h1,使用和:出现在底部的伪类:0左:0。但这意味着你的文字必须左对齐而不是中心。

当h1包装到2行时,h1大小基本上加倍,然后将导致if语句触发并将样式添加到文本中。这是我必须为你完美答案的最接近的答案,如果你要求文本为中心,我道歉。

编辑:上面的示例代码

现在我不能说这会起作用,但这里有一些基于前面解释过的方法的基本代码。我对javascript并不惊讶,所以你很可能需要继续构建。但至少这给了你一个起点我希望......

JS

$(document).ready(function() {
var h1Height = document.getElementsByTagName("h1").offsetHeight;

function firstH1Wrap() {
    if (h1Height < /*line-height+5px*/){
        document.getElementsByTagName("h1").addClass('hide-line');
    } else {
        document.getElementsByTagName("h1").removeClass('hide-line');
    }
}
});

$(window).resize(firstH1Wrap).trigger('resize')

CSS

h1, h2, h3, h4, h5, h6 {
    text-transform: uppercase;
    color: #000;
    margin-top: 0;
    margin-bottom: 2rem;
    font-weight: 800;
    color: #333;
    display: inline-block;
    position: relative;
    text-align: left;
    text-rendering: optimizeLegibility;
    font-family: $altfont;
    position: relative;
}

h1:after, h2:after, h3:after, h4:after, h5:after, h6:after {
    content: '';
    position: absolute;
    bottom:0;
    left:0;
    width: 60px;
    height: 4px;
    background-color: $yellow;
    display: block;
}

h1.hide-line:after, h2.hide-line:after, h3.hide-line:after, h4.hide-line:after, h5.hide-line:after, h6.hide-line:after {
    display: none;
}

如果您要将所有标题1-6的行高设置为相同,则可以为所有标题设置相同的功能,因为它们具有相同的大小,如果您不这样做,那么您将会这样做需要为每个标题声明一个新变量,并将其构建到函数中或创建新标题。

答案 3 :(得分:0)

根据您编写代码的方式,无法修复此问题。但是如果你愿意改变一些事情,我想我有一个解决方案。只有当您知道要处理的元素的font-size属性时,我的方法才有效。

更新CSS

h1 {
  font-size: 24px; /* ADDED */
  text-transform: uppercase;
  color: #000;
  margin-top: 0;
  margin-bottom: 2rem;
  font-weight: 800;
  color: #333;
  display: inline-block;
  position: relative;
  text-rendering: optimizeLegibility;
  font-family: $altfont;
  position: relative;

  &:after {
      content: '';
      position: absolute;
      top: 24px; /* FONT SIZE = DISTANCE */
      left:0;
      width: 60px;
      height: 4px;
      background-color: $yellow;
  }
}

这应该可行但是未经测试。

通过了解font-size然后使用该值作为上边距来工作。因此,无论文本对齐方式如何变化,它都将始终位于同一位置。

编辑:我现在明白您想要完成的任务。

这很难做到,因为这条线可能位于许多不同的位置。我能想到的唯一解决方案是:

媒体查询

您需要随时和每次文本换行或最后一行的第一个单词移动时创建断点。

答案 4 :(得分:0)

var text = $(this:last).text().trim().split(" ");
var last = text.pop();
$( this:last).html(text.join(" ") + (text.length > 0 ? " <span class='lastWord'>" + last + "</span>" : last));
};

在CSS中添加此

 .lastWord{text-decoration:underline;}

答案 5 :(得分:-3)

刚刚放了一个

top:'whatever is line-height + 20px'

到:after元素(并删除底部)

编辑:纳米 我错过了'我希望黄色线出现在“Slice”这个词下面。部分