Search code examples
jqueryhtmlcssribbon

Ribbon on heading with dynamic height + fixing the line break


I am trying to achieve a style for my headings similar to my logo which looks like this:

enter image description here

So I added some CSS for the heading to create some ribbons like so:

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>

It almost works as I want it but I have a few problems which I cant wrap my head around. I hope you can help me figuring out what I'm doing wrong:

  1. Depending on the viewports width, some of the headings sometimes have a 1px difference between the ribbon height and the headings background which leads to a visible step. How can I make sure the ribbon is always the same height as the heading - independent from the headings font, font-size and line-height?
  2. When the viewports is not wide enough and the text gets wrapped, the trailing ribbon gets overlayed by the heading. What can I do to achieve a look like in the logo where each line has its own background with some padding left and right to the text and the ribbon on the first and last line? The end result should look like the second image of "2" in the image below

enter image description here


Solution

  • Since this cannot be accomplished without nested elements, consider looping1 through every instance of a title element2 contained within a page, and wrapping each text node3 with an element that can be targeted as a selector4.

    Wrapping text nodes in a specified element

    1. This can be done using the jQuery .each() method
    2. Apply classes to these elements for dynamic scallability (e.g: .ribbon)
    3. This can be done using a for loop and combining/joining text nodes wrapped in a specified element
    4. In this case, the specified element is an inline span

    Declare the styles

    Styles will require adjusting, to declare the majority of the design properties to the the nested span elements.

    line-height and border-width properties, on pseudo-elements, should also be reconsidered for consistency throughout varying viewport sizes (preference may be given to absolute <length> values, using px units, rather than relative <length> values, using em units)

    .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 */
    }
    

    Code Snippet Demonstration:

    $('.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>