Search code examples
javascriptcsstypography

Remove whitespace from first and last character on multiple headline sizes


I try to get div fitting headlines, so far so good. But know I got problems with the default whitespace of the characters ( particularly with the even ones like I,L,P,H). I've tried to manage it with the letter spacing (doesn't work), than I've tried to solve it with text justification (didn't get a solution as well)... Does anybody know a way to handle it? Thanks

function scaleHeader() {
  var vw = ($(window).width())* 0.01;
  console.log(vw)
  var scalable = document.querySelectorAll('h1');
  for (var i = 0; i < scalable.length; i++) {
    var scalableContainer = scalable[i].parentNode;
    scalable[i].style.transform = 'scale(1)';
    var scalableContainerWidth = scalableContainer.offsetWidth; 
    
    var scalableWidth = scalable[i].offsetWidth;
    scalable[i].style.transform = 'scale(' + scalableContainerWidth / scalableWidth + ')';
    
    
    var firstletter = $(scalable[i]).text().slice(0,1);
    var lastletter = $(scalable[i]).text().slice(-1);
    
    if((firstletter.match(/(B|D|E|F|H|I|K|L|M|N|P|R|U|b|i|k|l|m|n|p|r)/)) && (lastletter.match(/(I|U|i|j|l|q|u)/))){
      //Here I don't know what to do!
    }
    
    if ($(scalableContainer).text().match(/(g|y|j|q|p)/)){
      scalableContainer.style.height = scalable[i].getBoundingClientRect().height * 1.05 + 'px' ;
    } else { 
      scalableContainer.style.height = scalable[i].getBoundingClientRect().height * 0.85 + 'px' ;
    }
  }  
}

scaleHeader();
window.addEventListener('resize', scaleHeader);
* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
  font-size: 32px;
  line-height: 32px;
}

body {
  font-family: sans-serif;
}

.third {
  display:inline-block;
  text-align: left;
  background-color: red;
  
  margin-bottom: 20px;
  width: 33vw;
  heigth: auto;
}

.half {
  display:inline-block;
  text-align: left;
  background-color: red;
  
  margin-bottom: 20px;
  width: 49.5vw;
  heigth: auto;
} 

.scale--js {
  display: inline-block;
  transform-origin: 0 0;
  transform: translate3d( 0, 0, 0);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>

<div class="third"> 
      <h1 class="scale--js">Mai</h1>  
</div>

<div class="third"> 
      <h1 class="scale--js">Juni</h1>   
</div>

<div class="third"> 
      <h1 class="scale--js">Heute</h1>  
</div>  

<div class="half">
    <h1 class="scale--js">A'm full widthq</h1>
</div> 

<div class="third"> 
      <h1 class="scale--js">ij</h1>   
</div>

<div class="half"> 
      <h1 class="scale--js">Aktuell</h1>
</div>


Solution

  • I solved it using a modifiction of bigtext.js. In case somebody else needs it.

    /*! BigText - v1.0.1 - 2017-06-01
     * https://github.com/zachleat/bigtext
     * Copyright (c) 2017 Zach Leatherman (@zachleat)
     * MIT License */
    
    (function(window, $) {
      "use strict";
    
      var counter = 0,
        $headCache = $('head'),
        oldBigText = window.BigText,
        oldjQueryMethod = $.fn.bigtext,
        BigText = {
          DEBUG_MODE: false,
          DEFAULT_MIN_FONT_SIZE_PX: null,
          DEFAULT_MAX_FONT_SIZE_PX: 100000000,
          GLOBAL_STYLE_ID: 'bigtext-style',
          STYLE_ID: 'bigtext-id',
          LINE_CLASS_PREFIX: 'bigtext-line',
          EXEMPT_CLASS: 'bigtext-exempt',
          noConflict: function(restore)
          {
            if(restore) {
              $.fn.bigtext = oldjQueryMethod;
              window.BigText = oldBigText;
            }
            return BigText;
          },
          supports: {
            wholeNumberFontSizeOnly: (function() {
              if( !( 'getComputedStyle' in window ) ) {
                return true;
              }
              var test = $('<div/>').css({
                  position: 'absolute',
                  'font-size': '14.1px',
                }).insertBefore( $('script').eq(0) ),
                computedStyle = window.getComputedStyle( test[0], null );
    
              var ret = computedStyle && computedStyle.getPropertyValue( 'font-size' ) === '14px';
              test.remove();
              return ret;
            })()
          },
          init: function() {
            if(!$('#'+BigText.GLOBAL_STYLE_ID).length) {
              $headCache.append(BigText.generateStyleTag(BigText.GLOBAL_STYLE_ID, ['.bigtext * { white-space: nowrap; } .bigtext > * { display: block; }',
                                              '.bigtext .' + BigText.EXEMPT_CLASS + ', .bigtext .' + BigText.EXEMPT_CLASS + ' * { white-space: normal; }']));
            }
          },
          bindResize: function(eventName, resizeFunction) {
            var timeoutId;
            $(window).unbind(eventName).bind(eventName, function() {
              if( timeoutId ) {
                clearTimeout( timeoutId );
              }
              timeoutId = setTimeout( resizeFunction, 100 );
            });
          },
          getStyleId: function(id)
          {
            return BigText.STYLE_ID + '-' + id;
          },
          generateStyleTag: function(id, css)
          {
            return $('<style>' + css.join('\n') + '</style>').attr('id', id);
          },
          clearCss: function(id)
          {
            var styleId = BigText.getStyleId(id);
            $('#' + styleId).remove();
          },
          generateCss: function(id, linesFontSizes, lineWordSpacings, minFontSizes)
          {
            var css = [];
    
            BigText.clearCss(id);
    
            for(var j=0, k=linesFontSizes.length; j<k; j++) {
              css.push('#' + id + ' .' + BigText.LINE_CLASS_PREFIX + j + ' {' +
                (minFontSizes[j] ? ' white-space: normal;' : '') +
                (linesFontSizes[j] ? ' font-size: ' + linesFontSizes[j] + 'px;' : '') +
                (lineWordSpacings[j] ? ' word-spacing: ' + lineWordSpacings[j] + 'px;' : '') +
                '}');
            }
    
            return BigText.generateStyleTag(BigText.getStyleId(id), css);
          },
          jQueryMethod: function(options)
          {
            BigText.init();
    
            options = $.extend({
              minfontsize: BigText.DEFAULT_MIN_FONT_SIZE_PX,
              maxfontsize: BigText.DEFAULT_MAX_FONT_SIZE_PX,
              childSelector: '',
              resize: true
            }, options || {});
    
            this.each(function()
            {
              var $t = $(this).addClass('bigtext'),
                maxWidth = $t.width(),
                id = $t.attr('id'),
                $children = options.childSelector ? $t.find( options.childSelector ) : $t.children();
    
              if(!id) {
                id = 'bigtext-id' + (counter++);
                $t.attr('id', id);
              }
    
              if(options.resize) {
                BigText.bindResize('resize.bigtext-event-' + id, function()
                {
                  // TODO only call this if the width has changed.
                  BigText.jQueryMethod.call($('#' + id), options);
                });
              }
    
              BigText.clearCss(id);
    
              $children.addClass(function(lineNumber, className)
              {
                // remove existing line classes.
                return [className.replace(new RegExp('\\b' + BigText.LINE_CLASS_PREFIX + '\\d+\\b'), ''),
                    BigText.LINE_CLASS_PREFIX + lineNumber].join(' ');
              });
    
              var sizes = BigText.calculateSizes($t, $children, maxWidth, options.maxfontsize, options.minfontsize);
              $headCache.append(BigText.generateCss(id, sizes.fontSizes, sizes.wordSpacings, sizes.minFontSizes));
    
            });
    
            return this.trigger('bigtext:complete');
          },
          testLineDimensions: function($line, maxWidth, property, size, interval, units, previousWidth)
          {
            var width;
            previousWidth = typeof previousWidth === 'number' ? previousWidth : 0;
            $line.css(property, size + units);
    
            width = $line.width();
    
            if(width >= maxWidth) {
        // console.log(width, ' previous: ' + previousWidth, property + ' at ' + interval, 'prior: ' + (parseFloat(size) - interval), 'new:' + parseFloat(size));
              $line.css(property, '');
    
              if(width === maxWidth) {
                return {
                  match: 'exact',
                  size: parseFloat((parseFloat(size) - 0.1).toFixed(3))
                };
              }
    
              // Since this is an estimate, we calculate how far over the width we went with the new value.
              // If this is word-spacing (our last resort guess) and the over is less than the under, we keep the higher value.
              // Otherwise, we revert to the underestimate.
              var under = maxWidth - previousWidth,
                over = width - maxWidth;
    
              return {
                match: 'estimate',
                size: parseFloat((parseFloat(size) - (property === 'word-spacing' && previousWidth && ( over < under ) ? 0 : interval)).toFixed(3))
              };
            }
    
            return width;
          },
          calculateSizes: function($t, $children, maxWidth, maxFontSize, minFontSize)
          {
            var $c = $t.clone(true)
              .addClass('bigtext-cloned')
              .css({
                fontFamily: $t.css('font-family'),
                textTransform: $t.css('text-transform'),
                wordSpacing: $t.css('word-spacing'),
                letterSpacing: $t.css('letter-spacing'),
                position: 'absolute',
                left: BigText.DEBUG_MODE ? 0 : -9999,
                top: BigText.DEBUG_MODE ? 0 : -9999
              })
              .appendTo(document.body);
    
            // font-size isn't the only thing we can modify, we can also mess with:
            // word-spacing and letter-spacing. WebKit does not respect subpixel
            // letter-spacing, word-spacing, or font-size.
            // TODO try -webkit-transform: scale() as a workaround.
            var fontSizes = [],
              wordSpacings = [],
              minFontSizes = [],
              ratios = [];
    
            $children.css('float', 'left').each(function() {
              var $line = $(this),
                // TODO replace 8, 4 with a proportional size to the calculated font-size.
                intervals = BigText.supports.wholeNumberFontSizeOnly ? [8, 4, 1] : [8, 4, 1, 0.1],
                lineMax,
                newFontSize;
    
              if($line.hasClass(BigText.EXEMPT_CLASS)) {
                fontSizes.push(null);
                ratios.push(null);
                minFontSizes.push(false);
                return;
              }
    
              // TODO we can cache this ratio?
              var autoGuessSubtraction = 32, // font size in px
                currentFontSize = parseFloat($line.css('font-size')),
                ratio = ( $line.width() / currentFontSize ).toFixed(6);
    
              newFontSize = parseInt( maxWidth / ratio, 10 ) - autoGuessSubtraction;
    
              outer: for(var m=0, n=intervals.length; m<n; m++) {
                inner: for(var j=1, k=10; j<=k; j++) {
                  if(newFontSize + j*intervals[m] > maxFontSize) {
                    newFontSize = maxFontSize;
                    break outer;
                  }
    
                  lineMax = BigText.testLineDimensions($line, maxWidth, 'font-size', newFontSize + j*intervals[m], intervals[m], 'px', lineMax);
                  if(typeof lineMax !== 'number') {
                    newFontSize = lineMax.size;
    
                    if(lineMax.match === 'exact') {
                      break outer;
                    }
                    break inner;
                  }
                }
              }
    
              ratios.push(maxWidth / newFontSize);
    
              if(newFontSize > maxFontSize) {
                fontSizes.push(maxFontSize);
                minFontSizes.push(false);
              } else if(!!minFontSize && newFontSize < minFontSize) {
                fontSizes.push(minFontSize);
                minFontSizes.push(true);
              } else {
                fontSizes.push(newFontSize);
                minFontSizes.push(false);
              }
            }).each(function(lineNumber) {
              var $line = $(this),
                wordSpacing = 0,
                interval = 1,
                maxWordSpacing;
    
              if($line.hasClass(BigText.EXEMPT_CLASS)) {
                wordSpacings.push(null);
                return;
              }
    
              // must re-use font-size, even though it was removed above.
              $line.css('font-size', fontSizes[lineNumber] + 'px');
    
              for(var m=1, n=3; m<n; m+=interval) {
                maxWordSpacing = BigText.testLineDimensions($line, maxWidth, 'word-spacing', m, interval, 'px', maxWordSpacing);
                if(typeof maxWordSpacing !== 'number') {
                  wordSpacing = maxWordSpacing.size;
                  break;
                }
              }
    
              $line.css('font-size', '');
              wordSpacings.push(wordSpacing);
            }).removeAttr('style');
    
            if( !BigText.DEBUG_MODE ) {
              $c.remove();
            } else {
              $c.css({
                'background-color': 'rgba(255,255,255,.4)'
              });
            }
    
            return {
              fontSizes: fontSizes,
              wordSpacings: wordSpacings,
              ratios: ratios,
              minFontSizes: minFontSizes
            };
          }
        };
    
      $.fn.bigtext = BigText.jQueryMethod;
      window.BigText = BigText;
    
    })(this, jQuery);
    
    
    
    //Here is my modification
    
    
    
    $(document).ready(function(){
    
      $('h1').bigtext({
        childSelector: '> p',
      });
    
    
      $('p').each(function() {
        var firstletter = $(this).text().slice(0,1);
        var lastletter = $(this).text().slice(-1);
        var fontSize = $(this).css('fontSize');
        var fontSizeRaw = parseInt(fontSize, 10);
    
        if((firstletter.match(/(B|D|E|F|H|I|K|L|M|N|P|R|U|b|i|k|l|m|n|p|r)/)) && (lastletter.match(/(I|U|i|j|l|q|u)/))){
          var mrg= - fontSizeRaw / 36;
    
    
          $(this).html(function (i, html) {
            var chars = $.trim(html).split("");
            return '<span>' + chars.join('</span><span>') + '</span>';
          });
    
          $(this).children(":first").css('marginLeft', mrg + 'px');
          $(this).children(":last").css('marginRight', mrg + 'px');
           
        } else if (firstletter.match(/(B|D|E|F|H|I|K|L|M|N|P|R|U|b|i|k|l|m|n|p|r)/)){
          var mrg= - fontSizeRaw / 36;
    
          $(this).html(function (i, html) {
            var chars = $.trim(html).split("");
            return html.replace(/\S/g, '<span>$&</span>');
          });
    
          $(this).children(":first").css('marginLeft', mrg + 'px');
           
        } else if (lastletter.match(/(I|U|i|j|l|q|u)/)){
          var mrg= - fontSizeRaw / 36;
    
          $(this).html(function (i, html) {
            var chars = $.trim(html).split("");
            return html.replace(/\S/g, '<span>$&</span>');
          });
    
          $(this).children(":last").css('marginRight', mrg + 'px');
           
        } else {
    
          $(this).html(function (i, html) {
            var chars = $.trim(html).split("");
            return html.replace(/\S/g, '<span>$&</span>');
          });
    
        }
    
        if ($(this).text().match(/(g|y|j|q|p)/)){
          $(this).children().css('marginTop', '-' + fontSizeRaw * 0.1 + 'px' );
          $(this).css('height', fontSizeRaw * 0.80 + 'px' );
        } else {
          $(this).children().css('marginTop', '-' + fontSizeRaw * 0.1 + 'px' );
          $(this).css('height', fontSizeRaw * 0.63 + 'px' );
        }
    
      });
    });
    *{
      font-family: "FoundersGroteskXCond-Med", sans-serif;
      margin: 0;
      padding: 0;
    }
    
    h1{ 
    	font-weight: normal;
    	margin: 0 !important
    }
    
    .quater{
      height: auto;
      width: 32.33333vw;
      background-color: red;
    }
    
    .half{
      width: 65.666vw;
      background-color: red;
    }
    
    .grid > div{
      display: inline-block;
    	margin: 0.5vw;
    }
    
    
    .ll{
      zoom: 103%;
    }
    
    p {
    	padding-top: 0;
        display: flex !important;
        justify-content: space-between;
        /*background-color: blue;*/
    }
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <div class="grid">
    
      <div class="quater">
        <h1>
          <p>Wolfgang Mattheuer</p>
        </h1>
      </div> 
    
      <div class="quater">
        <h1>
          <p>Palawi</p>
        </h1>
      </div> 
    
      <div class="quater">
        <h1>
          <p>Rog</p>
        </h1>
      </div> 
    
      <div class="quater">
        <h1>
          <p>News</p>
        </h1>
      </div>
    
        <div class="half">
        <h1>
          <p>Tanja Zimmermann</p>
        </h1>
      </div> 
    
      <div class="quater">
        <h1>
          <p>Heute</p>
        </h1>
      </div>
    
      <div class="quater">
        <h1>
          <p>News</p>
        </h1>
      </div>
    
      <div class="quater">
        <h1>
          <p>Heute</p>
        </h1>
      </div>
      
      <div class="half">
        <h1>
          <p>Juli</p>
        </h1>
      </div>
      
      <div class="quater">
        <h1>
          <p>Aktuell</p>
        </h1>
      </div>
    
      <div class="quater">
        <h1>
          <p>lll</p>
        </h1>
      </div>
      
     </body>