Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

[letter|word]-spacing tweak

* Pixel font-size now not required
* [letter|word]-spacing now tweaked in a one-off calculation
* Demo updated with info on IE6 and 7 pitfalls
* Demo updated to serve IE6 a fixed width layout
* CSS file updated to work-around IE7 non-support of "inherit"
  • Loading branch information...
commit 9d675c61155115dd51bf460cbf26d2d9e9538f55 1 parent 47fdfda
@freqdec authored
View
2  css/slabtext.css
@@ -1 +1 @@
-.slabtexted .slabtext{display:inline-block;white-space:nowrap}.slabtextinactive .slabtext{display:inline;white-space:normal}.slabtextdone .slabtext{display:block}
+.slabtexted .slabtext{display:-moz-inline-box;display:inline-block;white-space:nowrap}.slabtextinactive .slabtext{display:inline;white-space:normal;font-size:1em !important;letter-spacing:inherit !important;word-spacing:inherit !important;*letter-spacing:0 !important;*word-spacing:0 !important;}.slabtextdone .slabtext{display:block}
View
321 index.html
@@ -9,164 +9,182 @@
<style>
/* Note: I've not added the fontface files to the git repo */
@font-face
- {
- font-family: 'LeagueGothicRegular';
- src: url('League_Gothic-webfont.eot');
- src: url('League_Gothic-webfont.eot?#iefix') format('embedded-opentype'),
- url('League_Gothic-webfont.woff') format('woff'),
- url('League_Gothic-webfont.ttf') format('truetype'),
- url('League_Gothic-webfont.svg#LeagueGothicRegular') format('svg');
- font-weight: normal;
- font-style: normal;
- }
+ {
+ font-family: 'LeagueGothicRegular';
+ src: url('League_Gothic-webfont.eot');
+ src: url('League_Gothic-webfont.eot?#iefix') format('embedded-opentype'),
+ url('League_Gothic-webfont.woff') format('woff'),
+ url('League_Gothic-webfont.ttf') format('truetype'),
+ url('League_Gothic-webfont.svg#LeagueGothicRegular') format('svg');
+ font-weight: normal;
+ font-style: normal;
+ }
html,
body
- {
- background:#fcfcfc;
- color:#444;
- }
+ {
+ background:#fcfcfc;
+ color:#444;
+ }
body
- {
- font: 16px/1.8 helvetica, verdana, arial, sans-serif;
- width:80%;
- padding:20px 0;
- max-width:960px;
- margin:0 auto;
- }
-
+ {
+ font: 16px/1.8 "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif;
+ width:80%;
+ padding:20px 0;
+ max-width:960px;
+ margin:0 auto;
+ }
+ /* http://css-tricks.com/simple-styles-for-horizontal-rules/ */
+ hr
+ {
+ border: 0;
+ height: 1px;
+ background-image: -webkit-linear-gradient(left, rgba(0,0,0,0), rgba(0,0,0,0.75), rgba(0,0,0,0));
+ background-image: -moz-linear-gradient(left, rgba(0,0,0,0), rgba(0,0,0,0.75), rgba(0,0,0,0));
+ background-image: -ms-linear-gradient(left, rgba(0,0,0,0), rgba(0,0,0,0.75), rgba(0,0,0,0));
+ background-image: -o-linear-gradient(left, rgba(0,0,0,0), rgba(0,0,0,0.75), rgba(0,0,0,0));
+ }
.col-1
- {
- width:47.5%;
- margin:0 2.5% 0 0;
- float:left;
- }
+ {
+ width:47.5%;
+ margin:0 2.5% 0 0;
+ float:left;
+ }
.col-2
- {
- width:47.5%;
- margin:0 0 0 2.5%;
- float:left;
- }
+ {
+ width:47.5%;
+ margin:0 0 0 2.5%;
+ float:left;
+ }
.col-1 p,
.col-2 p
- {
- color:#888;
- font-size:80%;
- text-align:center;
- }
+ {
+ color:#888;
+ font-size:80%;
+ text-align:center;
+ }
a
- {
- color:#111;
- }
+ {
+ color:#111;
+ }
p
- {
- margin:0 0 1.5em 0;
- line-height:1.5em;
- }
+ {
+ margin:0 0 1.5em 0;
+ line-height:1.5em;
+ }
dt
- {
- font-family:monospace;
- }
+ {
+ font-family:monospace;
+ }
pre
- {
- line-height:1.2;
- }
+ {
+ line-height:1.2;
+ }
footer
- {
- border-top:3px double #aaa;
- padding-top:1em;
- }
+ {
+ border-top:3px double #aaa;
+ padding-top:1em;
+ }
footer section
- {
- border-bottom:3px double #aaa;
- padding-bottom:1em;
- margin-bottom:1em;
- }
+ {
+ border-bottom:3px double #aaa;
+ padding-bottom:1em;
+ margin-bottom:1em;
+ }
sup a
- {
- text-decoration:none;
- }
+ {
+ text-decoration:none;
+ }
#h4
- {
- clear:both;
- }
+ {
+ clear:both;
+ }
.amp
- {
- font-family:Baskerville,'Goudy Old Style',Palatino,'Book Antiqua',serif;
- font-style:italic;
- font-weight:lighter;
- }
+ {
+ font-family:Baskerville,'Goudy Old Style',Palatino,'Book Antiqua',serif;
+ font-style:italic;
+ font-weight:lighter;
+ }
/* Set font-sizes for the headings */
h1
- {
- text-align:left;
- font-family:'LeagueGothicRegular', "Impact", Charcoal, Arial Black, Gadget, Sans serif;
- text-transform: uppercase;
- line-height:1;
- color:#222;
- font-size: 45px;
- /* Remember to set the correct font weight if using fontface */
- font-weight:normal;
- }
+ {
+ text-align:left;
+ font-family:'LeagueGothicRegular', "Impact", Charcoal, Arial Black, Gadget, Sans serif;
+ text-transform: uppercase;
+ line-height:1;
+ color:#222;
+ font-size:300%;
+ /* Remember to set the correct font weight if using fontface */
+ font-weight:normal;
+ }
/* Smaller font-size for the side-by-side demo */
.col-1 h1,
.col-2 h1
- {
- font-size: 32px;
- }
+ {
+ font-size: 32px;
+ }
h2
- {
- font-size: 25px;
- }
+ {
+ font-size: 25px;
+ }
/* Adjust the line-height for all headlines that have been slabtexted */
.slabtexted h1
- {
- line-height:.9;
- }
+ {
+ line-height:.9;
+ }
/* Target specific lines in the preset Studio One demo */
.slabtexted #studio-one span:nth-child(2)
- {
- line-height:.8;
- }
+ {
+ line-height:.8;
+ }
.slabtexted #studio-one span:nth-child(3)
- {
- line-height:1.1;
- }
+ {
+ line-height:1.1;
+ }
/* Fun with media queries - resize your browser to view changes. */
@media screen and (max-width: 960px)
- {
- body
- {
- padding:10px 0;
- min-width:20em;
- }
- .col-1,
- .col-2
- {
- float:none;
- margin:0;
- width:100%;
- }
- h1
- {
- font-size:36px;
- }
- h2
- {
- font-size:22px;
- }
- }
+ {
+ body
+ {
+ padding:10px 0;
+ min-width:20em;
+ }
+ .col-1,
+ .col-2
+ {
+ float:none;
+ margin:0;
+ width:100%;
+ }
+ h1
+ {
+ font-size:36px;
+ }
+ h2
+ {
+ font-size:22px;
+ }
+ }
@media screen and (max-width: 460px)
- {
- h1
- {
- font-size:26px;
- }
- h2
- {
- font-size:18px;
- }
- }
+ {
+ h1
+ {
+ font-size:26px;
+ }
+ h2
+ {
+ font-size:18px;
+ }
+ }
+ </style>
+ <!--[if lte IE 6]>
+ <style>
+ body
+ {
+ width:960px;
+ margin:0 auto;
+ }
</style>
+ <![endif]-->
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
@@ -175,12 +193,12 @@
<h1 id="h1">slabText &ndash; a jQuery plugin for producing big, bold &amp; responsive headlines</h1>
<p>I&#8217;ve been wanting to attempt a port of Erik Loyer&#8217;s <a href="http://erikloyer.com/index.php/blog/the_slabtype_algorithm_part_1_background/">slabtype algorithm</a> for quite some time now and seeing Paravel&#8217;s <a href="http://fittextjs.com/">fittext</a> jQuery plugin, in combination with a gloriously hassle-free lunch hour gave me the impetus to attempt it. This is the result &ndash; resize the browser viewport to see the effect in action.</p>
<h2 id="h2">So what does the script do again?</h2>
- <p>Put simply, the script splits headlines into rows before resizing each row to fill the available horizontal space. The ideal number of characters to set on each row is calculated by dividing the available width by the CSS font-size &ndash; the script then uses this <em>ideal character count</em> to split the headline into word combinations that are displayed as separate rows of text. More <a href="#h11">examples</a> can be viewed further down the page.</p>
+ <p>Put simply, the script splits headlines into rows before resizing each row to fill the available horizontal space. The ideal number of characters to set on each row is calculated by dividing the available width by the CSS font-size &ndash; the script then uses this <em>ideal character count</em> to split the headline into word combinations that are displayed as separate rows of text. Many <a href="#h11">more examples</a> can be viewed further down the page.</p>
<h2 id="h3">Calculated and preset word combinations</h2>
<p>While the script does an admirable job at automating the creation of the individual rows, there are certainly situations in which you would choose to control the word combinations used to split the headline.</p>
- <p>This can be achieved by presetting the word combinations (using <code>&lt;span class="slabtext"&gt;</code> wrappers) within the markup<sup><a href="#fn1" id="r1">[1]</a></sup>. Should the script detect that the headline has been preset, it will not attempt to dynamically create the word combinations and simply fallback to resizing the given preset rows to fit the available horizontal space.</p>
- <p>Adding the <code>span</code> elements to the page markup in this way gives you absolute control over the word combinations used to split the headline text and also enables the targetting of specific rows within the CSS (in order to tweak the line-height, change the font family etc).</p>
- <p>Presetting the headline does have its drawbacks though &ndash; If the rows have wildly varying letter-counts, jagged right edges may be displayed. This can occassionally be seen in the second headline below where the penultimate row contains many more characters than the others.</p>
+ <p>This can be achieved by presetting the word combinations (using <code>&lt;span class="slabtext"&gt;</code> wrappers) within the markup<sup><a href="#fn1" id="r1">[1]</a></sup>. Should the script detect that the headline has been preset, it will not attempt to dynamically create the word combinations and simply fallback to resizing the preset rows to fit the available horizontal space.</p>
+ <p>Adding the <code>span</code> elements to the page markup in this way gives you absolute control over the word combinations used to split the headline text and also enables the targetting of specific rows within the CSS (in order to tweak the line height, change the font family etc).</p>
+ <p>Presetting the headline does have its drawbacks though &ndash; at smaller sizes and if the rows have wildly varying letter-counts, jagged right edges may be displayed. The script will adjust the <code>word-spacing</code> or <code>letter-spacing</code> in an attempt to rectify over-shoots or under-shoots in line length like this.</p>
<p>The following demo showcases two versions of the same headline, the first has rows (word combinations) dynamically calculated by the script while the second has rows preset within the markup (and therefore only resized-to-fit by the script).</p>
<div class="col-1">
<p>The following word combinations are calculated by the script</p>
@@ -194,14 +212,15 @@ <h2 id="h4">Being responsibly responsive</h2>
<p>You may wish to remove the slabtext treatment entirely should either the viewport or the header element resize to below a certain, predefined width; for example, if the viewport width drops to below 380 pixels. This can be achievied by using the <code>viewportBreakpoint</code> and <code>headerBreakpoint</code> plugin options, <a href="#h6">detailed below</a>.</p>
<p>This demo page has set <code>viewportBreakpoint</code> to be 380 pixels. Resizing the browser window to anything below this should remove the slabtext treatment from the headlines altogether.</p>
<h2 id="h5">Behind the scenes</h2>
- <p>In an attempt to keep the plugin as fast as possible, a very basic <code>font-size</code> calculation is ran whenever the <code>window.resize</code> event fires. Headlines that have been preset only fire steps 1, 2 and 6, skipping steps 3 through 5 completely. To save extra cpu cycles, the resize event has been throttled to 300ms.</p>
+ <p>In an attempt to keep the plugin as fast as possible, a very basic <code>font-size</code> calculation is ran whenever the <code>window.resize</code> event fires. Headlines that have been preset only fire steps 1, 2, 6 and, if required, 7 &ndash; skipping steps 3 through 5 completely. To save extra cpu cycles, the resize event has been throttled to 300ms.</p>
<ol>
- <li>The headlines pixel width is calculated</li>
- <li>The headlines pixel <code>font-size</code> is then calculated</li>
- <li>The ideal number of &#8220;characters per line&#8221; is derived by dividing the width (calculated in step 1) by the <code>font-size</code> (calculated in step 2) which itself is multiplied by the font scale ratio (which defaults to 0.78) e.g. for a parent container width of 800 pixels and a font-size of 45 pixels the ideal number of characters per line would be calculated using <code>Math.floor(800 / (45 &times; 0.78)) = 22</code></li>
+ <li>The headlines pixel width is calculated.</li>
+ <li>The headlines pixel <code>font-size</code> is then calculated.</li>
+ <li>The ideal number of &#8220;characters per line&#8221; is derived by dividing the width (calculated in step 1) by the <code>font-size</code> (calculated in step 2) which itself is multiplied by the font scale ratio (which defaults to 0.78) e.g. for a parent container width of 800 pixels and a font-size of 45 pixels the ideal number of characters per line would be calculated using <code>Math.floor(800 / (45 &times; 0.78)) = 22</code>.</li>
<li>The headline text is then split into words (by splitting on the space character) and these words arranged into combinations containing &lt;= the number of ideal characters per line (calculated in step 3).</li>
- <li>Each word combination is then wrapped in a <code>&lt;span class="slabtext"&gt;</code> element and the headline markup updated with the new content</li>
- <li>Each individual <code>span</code> then has its <code>font-size</code> adjusted by multiplying the current <code>font-size</code> by the ratio difference between the parent containers width (calculated in step 1) and the width of the <code>span</code></li>
+ <li>Each word combination is then wrapped in a <code>&lt;span class="slabtext"&gt;</code> element and the headline markup updated with the new content.</li>
+ <li>Each individual <code>span</code> then has its <code>font-size</code> adjusted by multiplying the current <code>font-size</code> by the ratio difference between the parent containers width (calculated in step 1) and the width of the <code>span</code>.</li>
+ <li>If required, each individual <code>span</code> then has either its <code>letter-spacing</code> (if the line contains only one word) or its <code>word-spacing</code> (if the line contains multiple words) adjusted in an attempt to prod the browser into rectifying over-shoots or under-shoots in line length caused by the previous <code>font-size</code> adjustment.</li>
</ol>
<h2 id="h6">Plugin options</h2>
<p>The following options can currently be passed to the plugin. The first three listed (<code>fontRatio</code>, <code>forceNewCharCount</code> and <code>wrapAmpersand</code>) are only used whenever the plugin has to dynamically create the word combinations i.e. if <code>&lt;span class="slabtext"&gt;</code> elements are <em>not</em> already present within the markup.</p>
@@ -224,13 +243,19 @@ <h2 id="h7">A note on the CSS</h2>
<p>The plugin requires the following CSS rules are made available:</p>
<pre><code>.slabtexted .slabtext
{
+ display:-moz-inline-box;
display:inline-block
white-space:nowrap;
}
.slabtextinactive .slabtext
{
display:inline;
- white-space:normal
+ white-space:normal;
+ font-size:1em !important;
+ letter-spacing:inherit !important;
+ word-spacing:inherit !important;
+ *letter-spacing:0 !important;
+ *word-spacing:0 !important;
}
.slabtextdone .slabtext
{
@@ -241,7 +266,8 @@ <h2 id="h7">A note on the CSS</h2>
<p>Using a double-whammy className inheritance trick like this means that you can safely add the <code>&lt;span class="slabtext"></code> elements into the markup but they won&#8217;t actually get styled until the script gets called and the <code>slabtexted</code> classname added to the <code>body</code>.</p>
<p>The <code>span</code> elements are set as <code>display:inline-block</code> during the font-size calculation. This is to take advantage of the <code>inline-block</code> shrink-wrap effect that enables the script to determine the width of each row.</p>
<p>Unfortunately, one side-effect of using <code>inline-block</code> means that the injected <code>span</code> elements react to surrounding whitespace (which, amongst other things, augments the vertical spacing between rows) &ndash; this is remedied by giving the header a classname of <code>slabtextdone</code> whenever the <code>font-size</code> calculation is complete, which sets a <code>display:block</code> style and avoids the whitespace and styling issues associated with <code>inline-block</code>.</p>
- <p>The CSS file is miniscule though and you may be better off pasting the contents into your main CSS file to avoid an unnecessary HTTP request.</p>
+ <p>Sharp-eyed readers may have noticed that the value of zero is passed to Internet Explorer using the star-hack. This is because IE &lt; 8 doesn&#8217;t understand the <code>inherit</code> property and so we reset to zero as a failsafe.</p>
+ <p>The CSS file is miniscule though and you may be better off pasting the contents of the minified version bundled with the download into your main CSS file to avoid an unnecessary HTTP request.</p>
<h2 id="h8">Buyer beware</h2>
<p>Here are a few things to remember when using the plug-in:</p>
<ol>
@@ -250,25 +276,36 @@ <h2 id="h8">Buyer beware</h2>
<li>The element to be given the slabText treatment has its (inner)HTML replaced entirely (by using the jQuery <code>.html</code> method), which means that all images and links contained within will disappear without a trace.</li>
<li>Unlike the original <a href="http://erikloyer.com/index.php/blog/the_slabtype_algorithm_part_1_background/">slabtype algorithm</a>, vertical space is not taken into consideration at all.</li>
<li>I&#8217;ve no idea how the script behaves in a right-to-left environment.</li>
- <li>Untested in older versions of IE although, in theory, there&#8217;s nothing that even IE6 can&#8217;t handle.</li>
+ <li>Internet Explorer 6, due to its non-support of <code>inline-block</code>, cannot scale <em>down</em> the text when the browser viewport is reduced in width. This may not be an issue if you serve a fixed width design to IE6 and fluid width design to other browsers.</li>
+ <li>Internet Explorer 7 does not support the CSS value of <code>inherit</code> which means that the <code>letter-spacing</code> and <code>word-spacing</code> have to get reset to zero whenever the slabText treatment is removed by the script.</li>
<li>Always call the script <em>after</em> all <code>fontface</code> fonts have downloaded (if using). I&#8217;ve hacked this for the demo to enable you to see the headline transformation as the script kicks-in but you should always use google WebFont loaders <code>active()</code> and <code>inactive()</code> callbacks to launch the slabText treatment (or a similar "font loaded" callback feature from another font provider).</li>
</ol>
<h2 id="h9">Credit where credit is due</h2>
<p>Based on the nice, shiny <a href="http://fittextjs.com/">fittext</a> jQuery plugin by <a href="http://paravelinc.com/">Paravel</a> &amp; the wonderful <a href="http://erikloyer.com/index.php/blog/the_slabtype_algorithm_part_1_background/">slabtype algorithm</a> by Erik Loyer. Zach Leatherman has also written a jQuery plugin named <a href="http://www.zachleat.com/web/bigtext-makes-text-big/">BigText</a> with similar but not exact functionality which is well worth a visit.</p>
<h2 id="h10">Grab the code</h2>
- <p>The code can be <a href="http://github.com/freqDec/slabText/">downloaded from github</a>. Both minified and unminified versions are included within the bundle. The minified version currently clocks-in at just over 2k &ndash; this drops to 1k when gzipped.</p>
+ <p>The code can be <a href="http://github.com/freqDec/slabText/">downloaded from github</a>. Both minified and unminified versions are included within the bundle. The minified version currently clocks-in at 3k &ndash; this drops to around 2k when gzipped.</p>
<h2 id="h11">A few more examples</h2>
<p>As way of example, here&#8217;s a random assortment of book titles (Note: I&#8217;ve left widowed words in all of them).</p>
- <!-- Yeah, yeah - h1's after an h2. It's horrible but not the end of the world, only a demo. Apologies to those offended. -->
+ <!-- Yeah, yeah - multiple h1's etc. It's horrible but not the end of the world. Apologies to those offended. -->
<h1>The Sisters Brothers</h1>
+ <hr />
<h1>The curious incident of the dog in the night</h1>
+ <hr />
<h1>Something Happened</h1>
+ <hr />
<h1>The sad tale of the brothers Grossbart</h1>
+ <hr />
<h1>The Windup Girl</h1>
+ <hr />
<h1>When Gravity Fails</h1>
+ <hr />
<h1>Psychotic Reactions and Carburetor Dung</h1>
+ <hr />
<h1>Mortal Engines</h1>
+ <hr />
<h1>Mansfield Park</h1>
+ <hr />
+ <h1>The Importance of being Earnest</h1>
<footer>
<section>
<p id="fn1"><a href="#r1">(1)</a> Of course, you can always use Javascript to inject the <code>&lt;span class="slabtext"&gt;</code> elements into the headline before calling the plugin &ndash; which would keep the markup squeaky clean and cruft free. Here&#8217;s a quick example of how it might be done:</p>
View
345 js/jquery.slabtext.js
@@ -1,170 +1,195 @@
-/*! jQuery slabtext plugin v1 MIT/GPL2 @freqdec */
-(function( $ ){
-
- $.fn.slabText = function(options) {
+/*! jQuery slabtext plugin v2 MIT/GPL2 @freqdec */
+(function( $ ){
- var settings = {
- // The ratio used when calculating the characters per line (parent width / (font-size * fontRatio))
- // You may wish to tweak this to suit your chosen font
- "fontRatio" : 0.78,
- // Always recalculate the characters per line, not just when the font-size changes?
- // Defaults to true (CPU intensive)
- "forceNewCharCount" : true,
- // Do we wrap ampersands in <span class="amp"> ?
- "wrapAmpersand" : true,
- // Under what pixel width do we remove the slabtext styling?
- "headerBreakpoint" : null,
- "viewportBreakpoint" : null,
- // Don't attach a resize event
- "noResizeEvent" : false
- };
+ $.fn.slabText = function(options) {
+
+ var settings = {
+ // The ratio used when calculating the characters per line
+ // (parent width / (font-size * fontRatio)).
+ "fontRatio" : 0.78,
+ // Always recalculate the characters per line, not just when the
+ // font-size changes? Defaults to true (CPU intensive)
+ "forceNewCharCount" : true,
+ // Do we wrap ampersands in <span class="amp"> ?
+ "wrapAmpersand" : true,
+ // Under what pixel width do we remove the slabtext styling?
+ "headerBreakpoint" : null,
+ "viewportBreakpoint" : null,
+ // Don't attach a resize event
+ "noResizeEvent" : false
+ };
+
+ // Add the slabtexted classname to the body to initiate the styling of
+ // the injected spans
+ $("body").addClass("slabtexted");
+
+ return this.each(function(){
+
+ // Extend options if necessary
+ if(options) {
+ $.extend(settings, options);
+ };
+
+ var $this = $(this),
+ keepSpans = $("span.slabtext", $this).length,
+ words = keepSpans ? [] : String($.trim($this.text())).replace(/\s{2,}/g, " ").split(" "),
+ origFontSize = null,
+ idealCharPerLine = null,
+ fontRatio = settings.fontRatio,
+ forceNewCharCount = settings.forceNewCharCount,
+ headerBreakpoint = settings.headerBreakpoint,
+ viewportBreakpoint = settings.viewportBreakpoint,
+ resizeThrottle = null,
+ viewportWidth = $(window).width();
+
+ // Calculates the pixel equivalent of 1em within the current header
+ var grabPixelFontSize = function() {
+ var dummy = jQuery('<div style="display:none;font-size:1em;margin:0;padding:0;height:auto;line-height:1;border:0;">&nbsp;</div>').appendTo($this),
+ emH = dummy.height();
+ dummy.remove();
+ return emH;
+ };
+
+ // Most of this function is a (very) stripped down AS3 to JS port of the slabtype
+ // algorithm by Eric Loyer with the original comments left intact
+ // http://erikloyer.com/index.php/blog/the_slabtype_algorithm_part_1_background/
+ var resizeSlabs = function resizeSlabs() {
+
+ // Cache the parent containers width
+ var parentWidth = $this.width(),
+ fs;
- // Add the slabtexted classname to the body to initiate the styling of
- // the injected spans
- $("body").addClass("slabtexted");
+ // Remove the slabtextdone and slabtextinactive classnames to enable the inline-block shrink-wrap effect
+ $this.removeClass("slabtextdone slabtextinactive");
- return this.each(function(){
-
- // Extend options if necessary
- if(options) {
- $.extend(settings, options);
- };
-
- var $this = $(this),
- keepSpans = $("span.slabtext", $this).length,
- words = keepSpans ? [] : String($.trim($this.text())).replace(/\s{2,}/g, " ").split(" "),
- origFontSize = null,
- idealCharPerLine = null,
- fontRatio = settings.fontRatio,
- forceNewCharCount = settings.forceNewCharCount,
- headerBreakpoint = settings.headerBreakpoint,
- viewportBreakpoint = settings.viewportBreakpoint,
- resizeThrottle = null,
- viewportWidth = $(window).width();
-
- // Most of this function is a (very) stripped down AS3 to JS port of the slabtype
- // algorithm by Eric Loyer with the original comments left intact
- // http://erikloyer.com/index.php/blog/the_slabtype_algorithm_part_1_background/
- var resizeSlabs = function resizeSlabs() {
-
- // Cache the parent containers width
- var parentWidth = $this.width();
-
- // Remove the slabtextdone and slabtextinactive classnames to enable the inline-block shrink-wrap effect
- $this.removeClass("slabtextdone slabtextinactive");
-
- if(viewportBreakpoint && viewportBreakpoint > viewportWidth
- ||
- headerBreakpoint && headerBreakpoint > parentWidth) {
- // Add the slabtextinactive classname to set the spans as inline
- $this.addClass("slabtextinactive");
- $("span.slabtext", $this).each(function() {
- $(this).css('font-size', "inherit");
- });
- return;
- };
-
- // If the parent containers font-size has changed or the "forceNewCharCount" option is true (the default),
- // then recalculate the "characters per line" count and re-render the inner spans
- // Setting "forceNewCharCount" to false will save CPU cycles...
- if(!keepSpans && (forceNewCharCount || parseFloat($this.css('font-size')) != origFontSize)) {
-
- origFontSize = parseFloat($this.css('font-size'));
-
- var newCharPerLine = Math.min(60, Math.floor(parentWidth / (origFontSize * fontRatio))),
- wordIndex = 0,
- lineText = [],
- counter = 0,
- preText = "",
- postText = "",
- finalText = "",
- preDiff,
- postDiff;
-
- if(newCharPerLine != idealCharPerLine) {
- idealCharPerLine = newCharPerLine;
-
- while (wordIndex < words.length) {
-
- postText = "";
-
- // build two strings (preText and postText) word by word, with one
- // string always one word behind the other, until
- // the length of one string is less than the ideal number of characters
- // per line, while the length of the other is greater than that ideal
- while (postText.length < idealCharPerLine) {
- preText = postText;
- postText += words[wordIndex] + " ";
- if(++wordIndex >= words.length) {
- break;
- };
- };
-
- // calculate the character difference between the two strings and the
- // ideal number of characters per line
- preDiff = idealCharPerLine - preText.length;
- postDiff = postText.length - idealCharPerLine;
-
- // if the smaller string is closer to the length of the ideal than
- // the longer string, and doesn’t contain just a single character, then
- // use that one for the line
- if((preDiff < postDiff) && (preText.length > 2)) {
- finalText = preText;
- wordIndex--;
- // otherwise, use the longer string for the line
- } else {
- finalText = postText;
- };
+ if(viewportBreakpoint && viewportBreakpoint > viewportWidth
+ ||
+ headerBreakpoint && headerBreakpoint > parentWidth) {
+ // Add the slabtextinactive classname to set the spans as inline
+ // and to reset the font-size to 1em (inherit won't work in IE7)
+ $this.addClass("slabtextinactive");
+ return;
+ };
+
+ fs = grabPixelFontSize();
+ // If the parent containers font-size has changed or the "forceNewCharCount" option is true (the default),
+ // then recalculate the "characters per line" count and re-render the inner spans
+ // Setting "forceNewCharCount" to false will save CPU cycles...
+ if(!keepSpans && (forceNewCharCount || fs != origFontSize)) {
- lineText.push('<span class="slabtext">' + (settings.wrapAmpersand ? finalText.replace("&", '<span class="amp">&amp;</span>') : finalText) + "</span>");
- };
-
- $this.html(lineText.join(""));
- };
- } else {
- // We only need the font-size for the resize-to-fit functionality
- // if not injecting the spans
- origFontSize = parseFloat($this.css('font-size'));
+ origFontSize = fs;
+
+ var newCharPerLine = Math.min(60, Math.floor(parentWidth / (origFontSize * fontRatio))),
+ wordIndex = 0,
+ lineText = [],
+ counter = 0,
+ preText = "",
+ postText = "",
+ finalText = "",
+ preDiff,
+ postDiff;
+
+ if(newCharPerLine != idealCharPerLine) {
+ idealCharPerLine = newCharPerLine;
+
+ while (wordIndex < words.length) {
+
+ postText = "";
+
+ // build two strings (preText and postText) word by word, with one
+ // string always one word behind the other, until
+ // the length of one string is less than the ideal number of characters
+ // per line, while the length of the other is greater than that ideal
+ while (postText.length < idealCharPerLine) {
+ preText = postText;
+ postText += words[wordIndex] + " ";
+ if(++wordIndex >= words.length) {
+ break;
};
-
- // Loop through the spans changing font-size accordingly
- $("span.slabtext", $this).each(function() {
- var $span = $(this),
- ratio = parentWidth / $span.width(),
- fontSize = parseFloat(this.style.fontSize) || origFontSize;
-
- $span.css('font-size', (fontSize * ratio) + "px");
- });
-
- // Add the class slabtextdone to set a display:block on the child spans
- // and avoid styling & layout issues associated with inline-block
- $this.addClass("slabtextdone");
+ };
+
+ // calculate the character difference between the two strings and the
+ // ideal number of characters per line
+ preDiff = idealCharPerLine - preText.length;
+ postDiff = postText.length - idealCharPerLine;
+
+ // if the smaller string is closer to the length of the ideal than
+ // the longer string, and doesn’t contain just a single character, then
+ // use that one for the line
+ if((preDiff < postDiff) && (preText.length > 2)) {
+ finalText = preText;
+ wordIndex--;
+ // otherwise, use the longer string for the line
+ } else {
+ finalText = postText;
+ };
+
+ lineText.push('<span class="slabtext">' + (settings.wrapAmpersand ? finalText.replace("&", '<span class="amp">&amp;</span>') : finalText) + "</span>");
};
-
- // Immediate resize
- resizeSlabs();
+
+ $this.html(lineText.join(""));
+ };
+ } else {
+ // We only need the font-size for the resize-to-fit functionality
+ // if not injecting the spans
+ origFontSize = fs;
+ };
+
+ // Loop through the spans changing font-size accordingly
+ $("span.slabtext", $this).each(function() {
+ var $span = $(this),
+ innerText = $span.text(),
+ wordSpacing = innerText.split(" ").length > 1,
+ diff,
+ ratio,
+ fontSize;
- if(!settings.noResizeEvent) {
- // Window resize event
- $(window).resize(function() {
- // Only run the resize code if the viewport width has changed.
- // we ignore the viewport height as it will be constantly changing
- // due to the font-size resizing and IE fires a resize event whenever
- // vertical height has changed leading to an endless loop and
- // locked browser. Poor IE.
-
- // Could wrap this in conditional comments?
- if($(window).width() == viewportWidth) {
- return;
- };
-
- viewportWidth = $(window).width();
-
- // Throttle the resize event to 300ms
- clearTimeout(resizeThrottle);
- resizeThrottle = setTimeout(resizeSlabs, 300);
- });
- };
+ $span.css('word-spacing', 0).css('letter-spacing', 0);
+
+ ratio = parentWidth / $span.width();
+ fontSize = parseFloat(this.style.fontSize) || origFontSize;
+
+ // Resize font
+ $span.css('font-size', (fontSize * ratio).toFixed(3) + "px");
+
+ // Do we still have space to try to fill or crop
+ diff = parentWidth - $span.width();
+
+ // A "dumb" tweak in the blind hope that the browser will
+ // resize the text to better fit the available space.
+ // Better "dumb" and fast...
+ if(diff) {
+ $span.css((wordSpacing ? 'word' : 'letter') + '-spacing', (diff / (wordSpacing ? innerText.split(" ").length - 1 : innerText.length)).toFixed(3) + "px");
+ };
+ });
+
+ // Add the class slabtextdone to set a display:block on the child spans
+ // and avoid styling & layout issues associated with inline-block
+ $this.addClass("slabtextdone");
+ };
+
+ // Immediate resize
+ resizeSlabs();
+
+ if(!settings.noResizeEvent) {
+ // Window resize event
+ $(window).resize(function() {
+ // Only run the resize code if the viewport width has changed.
+ // we ignore the viewport height as it will be constantly changing
+ // due to the font-size resizing and IE fires a resize event whenever
+ // vertical height has changed leading to an endless loop and
+ // locked browser.
+ if($(window).width() == viewportWidth) {
+ return;
+ };
+
+ viewportWidth = $(window).width();
+
+ // Throttle the resize event to 300ms
+ clearTimeout(resizeThrottle);
+ resizeThrottle = setTimeout(resizeSlabs, 300);
});
+ };
+ });
};
})(jQuery);
View
4 js/jquery.slabtext.min.js
@@ -1,2 +1,2 @@
-/*! jQuery slabtext plugin v1 MIT/GPL2 @freqdec */
-(function($){$.fn.slabText=function(options){var settings={fontRatio:0.78,forceNewCharCount:true,wrapAmpersand:true,headerBreakpoint:null,viewportBreakpoint:null,noResizeEvent:false};$("body").addClass("slabtexted");return this.each(function(){if(options){$.extend(settings,options);}var $this=$(this),keepSpans=$("span.slabtext",$this).length,words=keepSpans?[]:String($this.text()).replace(/\s{2,}/g).split(" "),origFontSize=null,idealCharPerLine=null,fontRatio=settings.fontRatio,forceNewCharCount=settings.forceNewCharCount,headerBreakpoint=settings.headerBreakpoint,viewportBreakpoint=settings.viewportBreakpoint,resizeThrottle=null,viewportWidth=$(window).width();var resizeSlabs=function resizeSlabs(){var parentWidth=$this.width();$this.removeClass("slabtextdone slabtextinactive");if(viewportBreakpoint&&viewportBreakpoint>viewportWidth||headerBreakpoint&&headerBreakpoint>parentWidth){$this.addClass("slabtextinactive");$("span.slabtext",$this).each(function(){$(this).css("font-size","inherit");});return;}if(!keepSpans&&(forceNewCharCount||parseFloat($this.css("font-size"))!=origFontSize)){origFontSize=parseFloat($this.css("font-size"));var newCharPerLine=Math.min(60,Math.floor(parentWidth/(origFontSize*fontRatio))),wordIndex=0,lineText=[],counter=0,preText="",postText="",finalText="",preDiff,postDiff;if(newCharPerLine!=idealCharPerLine){idealCharPerLine=newCharPerLine;while(wordIndex<words.length){postText="";while(postText.length<idealCharPerLine){preText=postText;postText+=words[wordIndex]+" ";if(++wordIndex>=words.length){break;}}preDiff=idealCharPerLine-preText.length;postDiff=postText.length-idealCharPerLine;if((preDiff<postDiff)&&(preText.length>2)){finalText=preText;wordIndex--;}else{finalText=postText;}lineText.push('<span class="slabtext">'+(settings.wrapAmpersand?finalText.replace("&",'<span class="amp">&amp;</span>'):finalText)+"</span>");}$this.html(lineText.join(""));}}else{origFontSize=parseFloat($this.css("font-size"));}$("span.slabtext",$this).each(function(){var $span=$(this),ratio=parentWidth/$span.width(),fontSize=parseFloat(this.style.fontSize)||origFontSize;$span.css("font-size",(fontSize*ratio)+"px");});$this.addClass("slabtextdone");};resizeSlabs();if(!settings.noResizeEvent){$(window).resize(function(){if($(window).width()==viewportWidth){return;}viewportWidth=$(window).width();clearTimeout(resizeThrottle);resizeThrottle=setTimeout(resizeSlabs,300);});}});};})(jQuery);
+/*! jQuery slabtext plugin v2 MIT/GPL2 @freqdec */
+(function($){$.fn.slabText=function(options){var settings={fontRatio:0.78,forceNewCharCount:true,wrapAmpersand:true,headerBreakpoint:null,viewportBreakpoint:null,noResizeEvent:false};$("body").addClass("slabtexted");return this.each(function(){if(options){$.extend(settings,options)}var $this=$(this),keepSpans=$("span.slabtext",$this).length,words=keepSpans?[]:String($.trim($this.text())).replace(/\s{2,}/g," ").split(" "),origFontSize=null,idealCharPerLine=null,fontRatio=settings.fontRatio,forceNewCharCount=settings.forceNewCharCount,headerBreakpoint=settings.headerBreakpoint,viewportBreakpoint=settings.viewportBreakpoint,resizeThrottle=null,viewportWidth=$(window).width();var grabPixelFontSize=function(){var dummy=jQuery('<div style="display:none;font-size:1em;margin:0;padding:0;height:auto;line-height:1;border:0;">&nbsp;</div>').appendTo($this),emH=dummy.height();dummy.remove();return emH};var resizeSlabs=function resizeSlabs(){var parentWidth=$this.width(),fs;$this.removeClass("slabtextdone slabtextinactive");if(viewportBreakpoint&&viewportBreakpoint>viewportWidth||headerBreakpoint&&headerBreakpoint>parentWidth){$this.addClass("slabtextinactive");return}fs=grabPixelFontSize();if(!keepSpans&&(forceNewCharCount||fs!=origFontSize)){origFontSize=fs;var newCharPerLine=Math.min(60,Math.floor(parentWidth/(origFontSize*fontRatio))),wordIndex=0,lineText=[],counter=0,preText="",postText="",finalText="",preDiff,postDiff;if(newCharPerLine!=idealCharPerLine){idealCharPerLine=newCharPerLine;while(wordIndex<words.length){postText="";while(postText.length<idealCharPerLine){preText=postText;postText+=words[wordIndex]+" ";if(++wordIndex>=words.length){break}}preDiff=idealCharPerLine-preText.length;postDiff=postText.length-idealCharPerLine;if((preDiff<postDiff)&&(preText.length>2)){finalText=preText;wordIndex--}else{finalText=postText}lineText.push('<span class="slabtext">'+(settings.wrapAmpersand?finalText.replace("&",'<span class="amp">&amp;</span>'):finalText)+"</span>")}$this.html(lineText.join(""))}}else{origFontSize=fs}$("span.slabtext",$this).each(function(){var $span=$(this),innerText=$span.text(),wordSpacing=innerText.split(" ").length>1,diff,ratio,fontSize;$span.css("word-spacing",0).css("letter-spacing",0);ratio=parentWidth/$span.width();fontSize=parseFloat(this.style.fontSize)||origFontSize;$span.css("font-size",(fontSize*ratio).toFixed(3)+"px");diff=parentWidth-$span.width();if(diff){$span.css((wordSpacing?"word":"letter")+"-spacing",(diff/(wordSpacing?innerText.split(" ").length-1:innerText.length)).toFixed(3)+"px")}});$this.addClass("slabtextdone")};resizeSlabs();if(!settings.noResizeEvent){$(window).resize(function(){if($(window).width()==viewportWidth){return}viewportWidth=$(window).width();clearTimeout(resizeThrottle);resizeThrottle=setTimeout(resizeSlabs,300)})}})}})(jQuery);
Please sign in to comment.
Something went wrong with that request. Please try again.