See here: https://github.com/FWeinb/nthEverything
A Pen by Fabrice W. on CodePen.
| <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> |
See here: https://github.com/FWeinb/nthEverything
A Pen by Fabrice W. on CodePen.
| /* | |
| # 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(); |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script> |
| 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); | |
| } |