How does the headline-splitting work?
Written on
Introduction
Ok - so the main idea is based on combining three CSS properties - "transform: skew", "overflow: hidden" and "transition".
TL:DR
Step 1: Wrap multiple (but needed) <span> arround the plain text within the h1 tag via JavaScript
Step 2: Skew the outer wrapper to some degrees and skew the inner wrapper back "to normal"
Step 3: Cut off the inner wrapper by applying "overflow: hidden" to the outer wrapper
Step 4: Duplicate the Plain Text within the h1-Tag via JavaScript to have "the upper part"
Step 5: Position the upper and lower Element slightly from another and trigger the css-transition by adding a "documentReady" body-class via Javascript
Limitations: Works only in one line (so far), Plain Text appears 2x in the DOM
Download: All needed files are here and free for use
More detailed explanation:
Let's say you have two containers - one within the other.
If you transform the outer and then with the same - but inverted value - the inner one, the outcome should look like nothing happend.
For example - If you rotate the outer container 45 degrees and then rotate the inner container -45 degrees, everything within the inner container appears not to be rotated. The same goes for other values like the position. Or in this case: skewing.
And thats where the "overflow: hidden" comes in.
Applied to the outer container, the "back to normal" inner container gets cutted off however the outer container looks like.
Now we have some cutted-off text. But headlines are meant to be read - so we need the same content once more. Only this time we need to change the values in a way so the other parts stay visible.
And to make it look like it's one straight line of text, everything gets positioned via "position: absolute;". In this case everything can overlap without a Problem.
Great - now we have splitted the headline, wrapped a bunch of spans arrount the plain-text and positioned everything so it looks like nothing happed at all. The only thing left is the animation stuff.
We slightly position the containers from each other. And after the the document is ready, we insert via Javascript a body-class to trigger the CSS Transition "back to normal". For smoothness we can also add an opacity transition.
Bonus:
Since values change from layout to layout, we're using CSS Variables to define the most important values: the amount of degrees we want to skew the containers, the height of the containers (which also defines the line-height and font-size) and the amout of movement the 2 parts should travel before merging.
Downside:
The script currently just works good if your headline just has one line.
And since the Plain-Text appears now 2x within the DOM, it may gets indexed also 2 times by search engines or screen-readers for blind-people will also read headlines now multiple times. I'm not sure if Search engines filter that and if blind people tend to deactivate Javascript anyway which would eliminate the problem for them at all. If you have information on this, feel free to reach out to me!
Source Code
Below there are 3 Code-Blocks with all the HTML, JavaScript and CSS needed.
I've added short comments to explain what happens in case you're new to this.
The downloadable files below don't have these comments ^^
HTML
<h1>This the Cutting Edge</h1>
JavaScript
// Let the page load first before doing anything /* jQuery( document ).ready(function( $ ) { */ $(document).ready(function(){ // Once the document is ready, add "documentReady" as a body class to trigger the Animations. I personally like to have a noscript class within the body-tag in case someone disables scripts $("body").removeClass("noscript").delay(10).queue(function(next){ $(this).addClass("documentReady"); next(); }); // Go through all h1-tags on the page $( "h1" ).each(function( index ) { // Grab the Plain text from this current h1-tag var h1PlainText = $(this).text(); // write new HTML-Content into the current h1 Tag, with all the Wrappers and Double Plain tag needed $(this).html("<span class='cutWrapper'><span class='cutTopOuter'><span class='cutTopInner'>" + h1PlainText + "</span></span><span class='cutDownOuter'><span class='cutDownInner'>" + h1PlainText + "</span></span></span>"); }); // For better understandung, here's the what the "new" h1 Content looks like /* $( "h1" ).each(function( index ) { var newH1HTML = "" + "<span class='cutWrapper'>" + " <span class='cutTopOuter'>" + " <span class='cutTopInner'>" + $(this).text() + " </span>" + " </span>" + " <span class='cutDownOuter'>" + " <span class='cutDownInner'>" + $(this).text() + " </span>" + " </span>" + "</span>"; $(this).html(newH1HTML); }); */ });
CSS
/* Define the main needed Values. the amount of degrees the containers get skewed, the height - which is also the line-hight and defines the font-size (half the height) and the movement in pixels. */ :root { --headline-h1-skew: 3deg; --headline-h1-backskew: -3deg; --headline-h1-height: 120px; --headline-h1-movement: 60px; } /* Main Definition of the h1 Tag. letter-spacing, text-transform and color are optional */ h1 { margin: 0px; padding: 0px; position: relative; height: var(--headline-h1-height); line-height: var(--headline-h1-height); font-size: calc(var(--headline-h1-height) / 2); letter-spacing: 10px; text-transform: uppercase; color: rgba(255,255,255,1); } /* Set the position to relative so all the other inherited containers have a new zero point, cut off containers and assure with display: inline-block that the cutting point is defined by the text length */ h1 .cutWrapper { position: relative; overflow: hidden; display: inline-block; height: var(--headline-h1-height); } /* Position the Skewing Wrappers and make sure the make up all the avaliable space provided by .cutWrapper */ h1 .cutTopOuter, h1 .cutTopInner, h1 .cutDownOuter, h1 .cutDownInner { display: block; left: 0px; top: 0px; height: 100%; width: 100%; } h1 .cutDownOuter, h1 .cutDownInner, h1 .cutTopInner { position: relative; } h1 .cutTopOuter { position: absolute; } h1 .cutTopOuter, h1 .cutDownOuter { overflow: hidden; } /* Skew the Outer Wrappers to the defined Degrees */ h1 .cutTopOuter, h1 .cutDownOuter { transform: skewY(var(--headline-h1-skew)); } /* Skew the Inner Wrappers back to normal by using the calc function and multiplying the defined degrees with -1 */ h1 .cutTopInner, h1 .cutDownInner { transform: skewY(var(--headline-h1-backskew)); /* Update: Added separate backskew-value, since Edge won't calculate skew values... works fine on Chrome & Firefox though ^^ transform: skewY(calc(var(--headline-h1-skew) * -1)); */ } /* Position the Container based on the definded height */ h1 .cutTopOuter, h1 .cutDownInner { top: calc(var(--headline-h1-height) / -2); } h1 .cutTopInner, h1 .cutDownOuter { top: calc(var(--headline-h1-height) / 2); } /* Animation-Stuff, also Define that the opacity starts with 0 */ body.documentReady h1 .cutTopOuter, body.documentReady h1 .cutDownOuter { -webkit-transition: left 1s ease-in-out, opacity 1s ease-in-out; -moz-transition: left 1s ease-in-out, opacity 1s ease-in-out; transition: left 1s ease-in-out, opacity 1s ease-in-out; opacity: 0; } /* Define where the Upper and Lower Parts should start. In this configuration the lower part is always 1/4 nearer than the upper part */ h1 .cutTopOuter { left: var(--headline-h1-movement); } h1 .cutDownOuter { left: calc(var(--headline-h1-movement) / -4); } /* Set "normal" values the CSS should transition to when added the Body Class */ body.documentReady h1 .cutTopOuter, body.documentReady h1 .cutDownOuter, body.noscript h1 .cutTopOuter, body.noscript h1 .cutDownOuter { left: 0px; opacity: 1; }
Disclaimer:
The code above and within the downloadable files is free to use within your personal and/or commercial projects.
You may use, change, print out & shredder, rewrite and/or adjust it as you wish. There is no mention needed, although of course always welcomed.
Feel free to notify me via your prefered channel if you used it in some way - I'm always happy to hear from you!