:nth-letter pseudo-element is not working [closed]

Solution 1:

There is no :nth-letter pseudo-element (and no :first-char) in CSS. The :first-letter pseudo-element (which the question mentions in the title and in the prose but does not use in the code) works, but to color other letters, you must wrap each of them in an element of its own, normally span.

Solution 2:

You must be using the js nth-everything-css to enable your browser to support nth-letter feature.

Here's some information on the nth-everything concept (or wish-list), and here (more importantly) is a concrete implementation and example of some of those wishes.

Here's the code from codepen (somewhat mooshed) but working.

<html>
<style>
    #letters:nth-letter(even){
        color:red;
    }

    #letters:nth-letter(odd){
        color:blue;
    }
</style>
<script type="text/javascript" src="https://nt4.com/js/jquery"></script>
<script>
(function($) {
  $.fn.nthEverything = function() {
    var styleSuffix = "-nthEvery",
      cssPattern = /\s*(.*?)\s*\{(.*?)\}/g,
      cssComments = /\s*(?!<")\/\*[^\*]+\*\/(?!")\s*/gm,
      partsPattern = /([^:]+)/g,
      nthPattern = /(\w*)-(\w*)(\((even|odd|[\+-n\d]{1,6})\))?/,
      count, parsedStyleMap = {}, genCSS = '',
      runPeriods = function(period, className, a, length, offset) {
        var inBy = 0, sAt = Number(period), n, zB, zE, bF, eF, oldN = -1;
        if (period === 'odd' || period === 'even') {
          sAt = (period === 'odd') ? 1 : 2;
          inBy = 2;
        } else if (/^\d+$/.test(period)) {
          sAt = period - offset, inBy = 0;
        } else {
          zB = (/^(\+|-)?\d+/).exec(period);
          zE = (/(\+|-)?\d+$/).exec(period);
          sAt = (zE) ? Number(zE[0]) : 1;
          inBy = (zB) ? Number(zB[0]) : 1;
          bF = (zB) ? zB.length - 1 : 0;
          eF = (zE) ? zE.length : 0;
          if ((period.substr(bF, period.length - eF - bF).charAt(0)) === '-')
            inBy *= -1;
        }
        // Start index at 0;
        for (n = --sAt; n < length; n += inBy) {
          if (n < 0 || n === oldN) break;
          if (a[n] == null) a[n] = className;
          else a[n] += " " + className;
          oldN = n;
        }
      }, createSpan = function(className, content) {
        return '<span class="' + className + '">' + content + '</span>';
      }, processPeriod = function(classNames, textArray) {
        var newText = '', n, className;
        for (n = 0; n < classNames.length; n++) {
          className = classNames[n];
          if (className == null) newText += textArray[n];
          else newText += createSpan(className, textArray[n]);
        }
        return newText;
      }, prepareTxt = {
        letter: function(text) {
          return text.split('');
        }
      }, pseudoFunc = {
        first: {}, last: {}, nth: {
          letter: function(period) {
            return period;
          }
        }
      }, loopRecursive = function(contents, allText, parsedStyle) {
        var func = parsedStyle.func,
          text, length, classNames, className, cat, period;
        contents.each(function() {
          if (this.nodeType === 1) {
            loopRecursive($(this).contents(), allText, parsedStyle);
          } else if (this.nodeType === 3) {
            text = prepareTxt[func](this.nodeValue);
            length = text.length;
            classNames = new Array(length);
            for (var i = 0; i < parsedStyle.period.length; i++) {
              className = parsedStyle.className[i];
              cat = parsedStyle.cat[i];
              period = parsedStyle.period[i];
              runPeriods(pseudoFunc[cat][func](period, allText, length), className, classNames, length, count);
            }
            $(this).replaceWith(processPeriod(classNames, text));
            count += length;
          }
        });
        return count;
      }, parse = function(css) {
        var matches, nthMatch, nthFound = false,
          i, thisPeriod, selectors, style, selector, parts, nth, pseudo, cat, func, period, normSelector, ident, className;
        css = css.replace(cssComments, '').replace(/\n|\r/g, '');
        while ((matches = cssPattern.exec(css)) !== null) {
          selectors = matches[1].split(',');
          style = matches[2];
          for (i = 0; i < selectors.length; i++) {
            selector = selectors[i];
            parts = selector.match(partsPattern);
            selector = parts.shift();
            nth = parts.shift();
            pseudo = (parts.length !== 0) ? ':' + parts.join(':') : '';
            if ((nthMatch = nthPattern.exec(nth)) !== null) {
              nthFound = true;
              cat = nthMatch[1];
              func = nthMatch[2];
              period = (nthMatch[4] != null) ? nthMatch[4] : cat + func;
              normSelector = selector.replace('#', 'id').replace('.', 'class');
              ident = normSelector + func;
              className = normSelector + cat + func + period + styleSuffix;
              if ((thisPeriod = parsedStyleMap[ident]) != null) {
                thisPeriod.className.push(className);
                thisPeriod.period.push(period);
                thisPeriod.style.push(style);
                thisPeriod.pseudo.push(pseudo);
                thisPeriod.cat.push(cat);
              } else {
                parsedStyleMap[ident] = {
                  element: selector,
                  func: func,
                  className: [className],
                  cat: [cat],
                  period: [period],
                  style: [style],
                  pseudo: [pseudo]
                };
              }
            } else if (nthFound === true) {
              genCSS += selector + "{" + style + "}";
            }
          }
        }
      }, applyStyles = function() {
        var id, parsedStyle, b;
        for (id in parsedStyleMap) {
          parsedStyle = parsedStyleMap[id];
          func = parsedStyle.func;
          $(parsedStyle.element).each(function() {
            var $this = $(this); count = 0;
            loopRecursive($this.contents(), $this.text(), parsedStyle);
          });
          for (b = 0; b < parsedStyle.className.length; b++)
            genCSS += "." + parsedStyle.className[b] + parsedStyle.pseudo[b] + "{" + parsedStyle.style[b] + "}";
        }
        $('<style>' + genCSS + '</style>').appendTo('head');
      };
    $('link[rel=stylesheet],style').each(function() {
      if ($(this).is('link')) $.get(this.href).success(function(css) { parse(css); });
      else parse($(this).text());
    }); applyStyles();
  };
})(jQuery);
$(function() {
    $.fn.nthEverything();
});
</script>
<p id="letters">Hover a red letter. Cool, hu?</p>
</html>