【问题标题】:Ribbon on heading with dynamic height + fixing the line break具有动态高度的标题上的功能区 + 修复换行符
【发布时间】:2023-10-31 20:53:01
【问题描述】:

我正在尝试为我的标题实现一种类似于我的徽标的样式,如下所示:

所以我为标题添加了一些 CSS 来创建一些像这样的功能区:

body {
  text-align: center;
}
h1,
h2 {
    color: white;
    background-color: #f3a692;
    text-shadow: -1px 1px rgba(208,96,0,0.5);
    display: inline-block;
    line-height: 1.6em !important;
    padding: 0 10px !important;
    margin-bottom: 20px;
}

h1:before,
h2:before {
    border-left-color: transparent !important;
    transform: translateX(-100%);
}

h1:after,
h2:after {
    border-right-color: transparent !important;
}

h1:after,
h1:before,
h2:after,
h2:before {
    content: '';
    border-color: #f3a692;
    border-style: solid;
    border-width: 0.8em;
    position: absolute;
}
<body>
<h1>Hello World</h1>
<p>This is just a small test</p>
<h2>Okay, thats nice!</h2>
<p>Here is some more text for no particular reason.</p>
</body>

它几乎可以按我的意愿工作,但我有一些问题我无法解决。我希望你能帮助我弄清楚我做错了什么:

  1. 根据视口宽度,某些标题有时会在功能区高度和标题背景之间存在 1 像素的差异,从而导致可见的台阶。如何确保功能区始终与标题高度相同 - 独立于标题字体、字体大小和行高?
  2. 当视口不够宽且文本被换行时,尾随功能区会被标题覆盖。我可以做些什么来实现徽标中的外观,其中每行都有自己的背景,文本左右有一些填充以及第一行和最后一行的功能区?最终结果应该类似于下图中“2”的第二张图片

【问题讨论】:

    标签: jquery html css ribbon


    【解决方案1】:

    由于没有嵌套元素就无法实现这一点,请考虑循环1通过标题元素的每个实例2 包含在页面中,并将每个文本节点3 包含一个可以定位为选择器的元素4

    将文本节点包裹在指定元素中

    1. 这可以使用 jQuery .each() 方法来完成
    2. 为这些元素应用类以实现动态可扩展性(例如: .ribbon)
    3. 这可以使用for 循环和组合/加入来完成 包裹在指定元素中的文本节点
    4. 在这种情况下,指定的元素是inline span

    声明样式

    样式将需要调整,以将大部分设计属性声明为嵌套的span 元素。

    line-heightborder-width 属性,在 pseudo-elements 上,也应该重新考虑在不同视口大小中的一致性(可以优先考虑 absolute &lt;length&gt; 值,使用 px 单位,而不是 relative &lt;length&gt; 值,使用 em 单位)

    .ribbon {
        max-width: 92%; /* allow space to prevent pseudo-elements overflowing horizontally */
        word-wrap: break-word; /* allow word wrapping */
        margin: 0 auto 20px auto;
    }
    
    .ribbon span {
        color: white;
        background-color: #f3a692;
        text-shadow: -1px 1px rgba(208, 96, 0, 0.5);
        display: inline-block;
        line-height: 50px; /* adjusted */
        padding: 0 5px;
        box-sizing: border-box;
        margin-bottom: 10px; /* allow vertical spacing between sibling elements */
    }
    

    代码片段演示:

    $('.ribbon').each(function(){
      var textNodes = $(this).text().split(' ');
      var output = '';
      for(var i=0; i < textNodes.length; i++) {
          output += '<span>'+textNodes[i]+'</span>';
      }
      $(this).html(output);
    });
    /* || start additional */
    
    .ribbon {
        max-width: 92%; /* allow space, left & right, to prevent pseudo-elements overflowing horizontally */
        word-wrap: break-word; /* allow word wrapping */
        margin: 0 auto 20px auto;
    }
    
    .ribbon span {
        color: white;
        background-color: #f3a692;
        text-shadow: -1px 1px rgba(208, 96, 0, 0.5);
        display: inline-block;
        line-height: 50px; /* adjusted */
        padding: 0 5px;
        box-sizing: border-box;
        margin-bottom: 10px; /* allow vertical spacing between sibling elements */
    }
    
    .resize { /* for the sake of demonstration */
        resize: auto;
        display: block;
        overflow: hidden;
        height: 100%;
        border: 2px dashed gray;
        position: relative;
    }
    
    /* end additional */
    
    body {
      text-align: center;
      box-sizing: border-box; /* additional */
    }
    
    /*h1,
    h2 {
      color: white;
      background-color: #f3a692;
      text-shadow: -1px 1px rgba(208, 96, 0, 0.5);
      display: inline-block;
      line-height: 1.6em !important;
      padding: 0 10px !important;
      margin-bottom: 20px;
    }*/
    
    .ribbon:before,
    .ribbon:before {
      border-left-color: transparent !important;
      transform: translateX(-100%);
    }
    
    .ribbon:after,
    .ribbon:after {
      border-right-color: transparent !important;
    }
    
    .ribbon:after,
    .ribbon:before,
    .ribbon:after,
    .ribbon:before {
      content: '';
      border-color: #f3a692;
      border-style: solid;
      border-width: 25px; /* adjusted */ /* equal to half the line height of sibling span elements */
      position: absolute;
    }
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <body>
      <div class="resize">
        <h1 class="ribbon">Wrapping text nodes in a specified element.</h1>
        <h1 class="ribbon">Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</h1>
        <h2 class="ribbon">Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</h2>
      </div>
    </body>

    【讨论】:

    • 你是我的英雄。它完美地工作。我只需要确保标题本身与跨度具有相同的行高。我希望有一种方法可以通过 jQuery 设置前后元素的边框,这样一切都可以动态完成。我认为通过 jQuery 将样式添加到文档样式表中是可能的,但现在您的解决方案绝对足够了。非常感谢。
    【解决方案2】:

    我看到的解决您的问题的唯一解决方案是将线放在跨度中。 这样,您可以控制中断,并且随着宽度的减小,它们将被放置在单独的行中。这是工作的sn-p。

    span 元素上的::after::before 只是为了美观,所以线条看起来不会“被切断”。

    body {
      text-align: center;
      width:500px; /* only for demonstration purposes */
    }
    h1,
    h2 {
        color: white;
        background-color: transparent;
        text-shadow: -1px 1px rgba(208,96,0,0.5);
        display: inline-block;
        line-height: 1.6em !important;
        padding: 0 10px !important;
        margin-bottom: 20px;
        position:relative;
    }
    h1 span, h2 span {
         height: 1.6em !important; 
         background-color:#f3a692; 
         display:inline-block; 
         white-space:nowrap; 
         padding:0;
         margin-bottom:20px;
         position:relative;
    }
    h1 span::before, h1 span::after, h2 span::before, h2 span::after {
    content: ' '; 
    background-color:#f3a692; 
    position:absolute;
    left:-10px; 
    width:10px; 
    height:100%;
    }
    h1 span::before, h2 span::before { left:-10px; }
    h1 span::after, h2 span::after { left:auto; right:-10px; }
    h1:before,
    h2:before {
        border-left-color: transparent !important;
        transform: translateX(-100%);
    }
    
    h1:after,
    h2:after {
        border-right-color: transparent !important;
    }
    
    h1:after,
    h1:before,
    h2:after,
    h2:before {
        content: '';
        border-color: #f3a692;
        border-style: solid;
        border-width: 0.8em;
        position: absolute;
       
    }
    <body>
     <!-- Make sure there is no whitespace between spans and h1 -->
    <h1><span>Hello World </span><span>Some random text here</span></h1>
    <p>This is just a small test</p>
    <h2><span>Okay, thats nice!</span></h2>
    <p>Here is some more text for no particular reason.</p>
    </body>

    【讨论】: