<h1><p id="nthEverthing">nth-Everthing</p></h1>

<p id="letters">Hover a red letter. Cool, hu?</p>
<p id="pseudo">Pseudo elements are working</p>
<p id="click">Please click here</p>
<p id="flip">Every second letter is flipped</p>
<p id="crazy">Flip Hover Flip</p>
<p id="font">Zoom all the things!</p>
<p id="word">FirstWord some words Green some words LastWord</p>
<p id="firstLastWord">Hello from nth-everthing</p>
body{
 font-family:Helvetica, sans-serif;
  font-size:50px;
  text-align:center;
}

p, h1{
  padding:0;
  margin:20px;
}
h1{
  font-size:120px;
}

#nthEverthing:nth-letter(odd),
#nthEverthing:nth-letter(even){
  display:inline-block;
  text-transform:uppercase;
  width:80px;
  width:80px;
}

#nthEverthing:nth-letter(even){
  transform: scale(1) skewY(-15deg);

}
#nthEverthing:nth-letter(odd){
  transform: scale(1) skewY(15deg);
}



#letters:nth-letter(even),
#letters:nth-letter(odd){
  transition:all .4s;
}
#letters:nth-letter(odd):hover,
#letters:nth-letter(even){
  color:red;
}

#letters:nth-letter(odd){
  color:blue;
}

#letters:nth-letter(even):hover{
  color:yellow;
}


#pseudo:nth-letter(1):before,
#pseudo:nth-letter(1):after{
  content:'_'
}

#click:nth-word(2):before{
  content:'>>';
}
#click:nth-word(2):after{
  content:'<<'
}


#click:nth-word(2):hover:before{
  content:'>>>>';
}
#click:nth-word(2):hover:after{
  content:'<<<<'
}


#flip:nth-letter(2n){
  display:inline-block;
  margin:10px 10px;
 -webkit-transform: rotateY(180deg);
}

/* Crazy text animation */
#crazy:nth-letter(2n1){
  display:inline-block;
  margin:10px 20px;
  transition:all .4s;
  color:green;
}

#crazy:nth-letter(2n1):hover{
  transform:rotateZ(180deg);
  color:blue;
}

#font:nth-letter(n){
  font-size:20px;
  transition:all 1s linear;
}


#font:nth-letter(n):hover{
  font-size:90px;
}


#word:first-word{
  color:blue;
}

#word:nth-word(4){
  color:green;
}

p#word:last-word{
  color:red;
}

#firstLastWord:first-word{
   font-size:90px;
}

#firstLastWord:last-word{
  color:green;
  transition:rotate 1s;
}
#firstLastWord:last-word{
  display:inline-block;
  transform: rotateZ(180deg);
}
/*
# nth-Everthing made with js. #

##Implemented nth- ##
:nth-letter
:nth-word


## Implemented last-##
:last-word
:last-letter

## Implemented first- ##
:first-word (faster than :nth-word(1))


## Things that work ##

Add a hover effet to each odd letter
  .className:nth-letter(odd):hover{}


Add a hover effect to :before/:after
  .className:nth-letter(odd):hover:after{}



## Things that don't and will not work ##
.className:before:nth-letter



Read more: https://css-tricks.com/a-call-for-nth-everything/
*/

(function($) {

  /*jshint  loopfunc:true, onevar:true*/
  /*global  jQuery:true, browser:true */

  $.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})\))?/,
    wordSpacePattern  = /(\s*[^ ]+\s*)/g,
    wordSimplePattern = /\s+/,
    count,
    // To store the style per Selector
    parsedStyleMap = {},
    // CSS for the classes
    genCSS = '',


    runPeriods  = function(period, className, a, length, offset){
            var inBy       = 0,
                sAt        = +period,
                matches,
                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)?+(zE[0]):1;
                inBy = (zB)?+(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;
        sAt--;

        for (n=sAt;n<length;n+=inBy){
            if (n < 0 || n === oldN) break;
            if (a[n] === undefined){
                 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 === undefined){
                newText += textArray[n];
            }else{
                newText += createSpan(className, textArray[n]);
            }
        }
           return newText;
    },

    getClassNames  = function(parsedStyle, length, pFunc){
                   var classNames = new Array(length), i;
                   for (i=0;i<parsedStyle.period.length;i++){
                       runPeriods (pFunc(parsedStyle.period[i], length), parsedStyle.className[i], classNames, length);
                   }
                   return classNames;
    },

    prepareTxt = {
             word  : function(text){return text.match(wordSpacePattern);},
            letter: function(text){return text.split('');}
    },

    pseudoFunc = {
        first : {
            word :  function(period){
                     if (period === 'firstword') period = '1';
                     return period;
            }
        },
        last : {
            word : function(period, allText, length){
                    if (period === 'lastword') period = ''+allText.match(wordSpacePattern).length;
                    return period;
            }
        },
        nth : {
            letter : function (period){
                    return period;
            },
            word :  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]!==undefined)?nthMatch[4]:cat+func;

                   normSelector = selector.replace('#','id').replace('.', 'class');
                   ident        = normSelector + func;
                   className    = normSelector + cat + func + period + styleSuffix;

                  if ((thisPeriod = parsedStyleMap[ident]) !== undefined){
                      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+"}"; // Fix chained selectors.
              }
          }
       }
    },

    applyStyles = function(){
        var id, parsedStyle, func, b;
        for (id in parsedStyleMap){
               parsedStyle = parsedStyleMap[id];
               func = parsedStyle.func;

               $(parsedStyle.element).each(function(){
                   var $this     = $(this);
                   count = 0; // Set to 0. We use a recursive Loop here
                   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');
    };

    // Build CSS Rules
    $('link[rel=stylesheet],style').each(function() {
        if ($(this).is('link')) $.get(this.href).success(function(css) { parse(css); }); else parse($(this).text());
    });

    // Apply Styles.
    applyStyles();

  };
})(jQuery);

$.fn.nthEverything();
Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. //cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js