What I am looking for:
A way to style one HALF of a character. (In this case, half the letter being transparent)
What I have currently searched for and tried (With no luck):
Below is an example of what I am trying to obtain.
Does a CSS or JavaScript solution exist for this, or am I going to have to resort to images? I would prefer not to go the image route as this text will end up being generated dynamically.
UPDATE:
Since many have asked why I would ever want to style half of a character, this is why. My city had recently spent $250,000 to define a new "brand" for itself. This logo is what they came up with. Many people have complained about the simplicity and lack of creativity and continue to do so. My goal was to come up with this website as a joke. Type in 'Halifax' and you will see what I mean.
The <sup> tag defines superscript text. Superscript text appears half a character above the normal line, and is sometimes rendered in a smaller font.
We basically use a data-content attribute with the same content as the span holds, and then copy this to a layered :after element which displays it. We then hide the original text and apply a 50% height to the after element, this way the background color can only be applied to the bottom half.
You can simply use the CSS display property with the value inline-block to make a <div> not larger than its contents (i.e. only expand to as wide as its contents).
Feel free to fork and improve.
Demo: http://jsfiddle.net/arbel/pd9yB/1694/
This works on any dynamic text, or a single character, and is all automated. All you need to do is add a class on the target text and the rest is taken care of.
Also, the accessibility of the original text is preserved for screen readers for the blind or visually impaired.
Explanation for a single character:
Pure CSS. All you need to do is to apply .halfStyle
class to each element that contains the character you want to be half-styled.
For each span element containing the character, you can create a data attribute, for example here data-content="X"
, and on the pseudo element use content: attr(data-content);
so the .halfStyle:before
class will be dynamic and you won't need to hard code it for every instance.
Explanation for any text:
Simply add textToHalfStyle
class to the element containing the text.
// jQuery for automated mode jQuery(function($) { var text, chars, $el, i, output; // Iterate over all class occurences $('.textToHalfStyle').each(function(idx, el) { $el = $(el); text = $el.text(); chars = text.split(''); // Set the screen-reader text $el.html('<span style="position: absolute !important;clip: rect(1px 1px 1px 1px);clip: rect(1px, 1px, 1px, 1px);">' + text + '</span>'); // Reset output for appending output = ''; // Iterate over all chars in the text for (i = 0; i < chars.length; i++) { // Create a styled element for each character and append to container output += '<span aria-hidden="true" class="halfStyle" data-content="' + chars[i] + '">' + chars[i] + '</span>'; } // Write to DOM only once $el.append(output); }); });
.halfStyle { position: relative; display: inline-block; font-size: 80px; /* or any font size will work */ color: black; /* or transparent, any color */ overflow: hidden; white-space: pre; /* to preserve the spaces from collapsing */ } .halfStyle:before { display: block; z-index: 1; position: absolute; top: 0; left: 0; width: 50%; content: attr(data-content); /* dynamic content for the pseudo element */ overflow: hidden; color: #f00; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script> <p>Single Characters:</p> <span class="halfStyle" data-content="X">X</span> <span class="halfStyle" data-content="Y">Y</span> <span class="halfStyle" data-content="Z">Z</span> <span class="halfStyle" data-content="A">A</span> <hr/> <p>Automated:</p> <span class="textToHalfStyle">Half-style, please.</span>
(JSFiddle demo)
With this solution you can style left and right parts, individually and independently.
Everything is the same, only more advanced CSS does the magic.
jQuery(function($) { var text, chars, $el, i, output; // Iterate over all class occurences $('.textToHalfStyle').each(function(idx, el) { $el = $(el); text = $el.text(); chars = text.split(''); // Set the screen-reader text $el.html('<span style="position: absolute !important;clip: rect(1px 1px 1px 1px);clip: rect(1px, 1px, 1px, 1px);">' + text + '</span>'); // Reset output for appending output = ''; // Iterate over all chars in the text for (i = 0; i < chars.length; i++) { // Create a styled element for each character and append to container output += '<span aria-hidden="true" class="halfStyle" data-content="' + chars[i] + '">' + chars[i] + '</span>'; } // Write to DOM only once $el.append(output); }); });
.halfStyle { position: relative; display: inline-block; font-size: 80px; /* or any font size will work */ color: transparent; /* hide the base character */ overflow: hidden; white-space: pre; /* to preserve the spaces from collapsing */ } .halfStyle:before { /* creates the left part */ display: block; z-index: 1; position: absolute; top: 0; width: 50%; content: attr(data-content); /* dynamic content for the pseudo element */ overflow: hidden; pointer-events: none; /* so the base char is selectable by mouse */ color: #f00; /* for demo purposes */ text-shadow: 2px -2px 0px #af0; /* for demo purposes */ } .halfStyle:after { /* creates the right part */ display: block; direction: rtl; /* very important, will make the width to start from right */ position: absolute; z-index: 2; top: 0; left: 50%; width: 50%; content: attr(data-content); /* dynamic content for the pseudo element */ overflow: hidden; pointer-events: none; /* so the base char is selectable by mouse */ color: #000; /* for demo purposes */ text-shadow: 2px 2px 0px #0af; /* for demo purposes */ }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script> <p>Single Characters:</p> <span class="halfStyle" data-content="X">X</span> <span class="halfStyle" data-content="Y">Y</span> <span class="halfStyle" data-content="Z">Z</span> <span class="halfStyle" data-content="A">A</span> <hr/> <p>Automated:</p> <span class="textToHalfStyle">Half-style, please.</span>
(JSFiddle demo)
Now that we know what is possible, let's create some variations.
// jQuery for automated mode jQuery(function($) { var text, chars, $el, i, output; // Iterate over all class occurences $('.textToHalfStyle').each(function(idx, el) { $el = $(el); text = $el.text(); chars = text.split(''); // Set the screen-reader text $el.html('<span style="position: absolute !important;clip: rect(1px 1px 1px 1px);clip: rect(1px, 1px, 1px, 1px);">' + text + '</span>'); // Reset output for appending output = ''; // Iterate over all chars in the text for (i = 0; i < chars.length; i++) { // Create a styled element for each character and append to container output += '<span aria-hidden="true" class="halfStyle" data-content="' + chars[i] + '">' + chars[i] + '</span>'; } // Write to DOM only once $el.append(output); }); });
.halfStyle { position: relative; display: inline-block; font-size: 80px; /* or any font size will work */ color: transparent; /* hide the base character */ overflow: hidden; white-space: pre; /* to preserve the spaces from collapsing */ } .halfStyle:before { /* creates the top part */ display: block; z-index: 2; position: absolute; top: 0; height: 50%; content: attr(data-content); /* dynamic content for the pseudo element */ overflow: hidden; pointer-events: none; /* so the base char is selectable by mouse */ color: #f00; /* for demo purposes */ text-shadow: 2px -2px 0px #af0; /* for demo purposes */ } .halfStyle:after { /* creates the bottom part */ display: block; position: absolute; z-index: 1; top: 0; height: 100%; content: attr(data-content); /* dynamic content for the pseudo element */ overflow: hidden; pointer-events: none; /* so the base char is selectable by mouse */ color: #000; /* for demo purposes */ text-shadow: 2px 2px 0px #0af; /* for demo purposes */ }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script> <p>Single Characters:</p> <span class="halfStyle" data-content="X">X</span> <span class="halfStyle" data-content="Y">Y</span> <span class="halfStyle" data-content="Z">Z</span> <span class="halfStyle" data-content="A">A</span> <hr/> <p>Automated:</p> <span class="textToHalfStyle">Half-style, please.</span>
(JSFiddle demo)
// jQuery for automated mode jQuery(function($) { var text, chars, $el, i, output; // Iterate over all class occurences $('.textToHalfStyle').each(function(idx, el) { $el = $(el); text = $el.text(); chars = text.split(''); // Set the screen-reader text $el.html('<span style="position: absolute !important;clip: rect(1px 1px 1px 1px);clip: rect(1px, 1px, 1px, 1px);">' + text + '</span>'); // Reset output for appending output = ''; // Iterate over all chars in the text for (i = 0; i < chars.length; i++) { // Create a styled element for each character and append to container output += '<span aria-hidden="true" class="halfStyle" data-content="' + chars[i] + '">' + chars[i] + '</span>'; } // Write to DOM only once $el.append(output); }); });
.halfStyle { /* base char and also the right 1/3 */ position: relative; display: inline-block; font-size: 80px; /* or any font size will work */ color: transparent; /* hide the base character */ overflow: hidden; white-space: pre; /* to preserve the spaces from collapsing */ color: #f0f; /* for demo purposes */ text-shadow: 2px 2px 0px #0af; /* for demo purposes */ } .halfStyle:before { /* creates the left 1/3 */ display: block; z-index: 2; position: absolute; top: 0; width: 33.33%; content: attr(data-content); /* dynamic content for the pseudo element */ overflow: hidden; pointer-events: none; /* so the base char is selectable by mouse */ color: #f00; /* for demo purposes */ text-shadow: 2px -2px 0px #af0; /* for demo purposes */ } .halfStyle:after { /* creates the middle 1/3 */ display: block; z-index: 1; position: absolute; top: 0; width: 66.66%; content: attr(data-content); /* dynamic content for the pseudo element */ overflow: hidden; pointer-events: none; /* so the base char is selectable by mouse */ color: #000; /* for demo purposes */ text-shadow: 2px 2px 0px #af0; /* for demo purposes */ }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script> <p>Single Characters:</p> <span class="halfStyle" data-content="X">X</span> <span class="halfStyle" data-content="Y">Y</span> <span class="halfStyle" data-content="Z">Z</span> <span class="halfStyle" data-content="A">A</span> <hr/> <p>Automated:</p> <span class="textToHalfStyle">Half-style, please.</span>
(JSFiddle demo)
// jQuery for automated mode jQuery(function($) { var text, chars, $el, i, output; // Iterate over all class occurences $('.textToHalfStyle').each(function(idx, el) { $el = $(el); text = $el.text(); chars = text.split(''); // Set the screen-reader text $el.html('<span style="position: absolute !important;clip: rect(1px 1px 1px 1px);clip: rect(1px, 1px, 1px, 1px);">' + text + '</span>'); // Reset output for appending output = ''; // Iterate over all chars in the text for (i = 0; i < chars.length; i++) { // Create a styled element for each character and append to container output += '<span aria-hidden="true" class="halfStyle" data-content="' + chars[i] + '">' + chars[i] + '</span>'; } // Write to DOM only once $el.append(output); }); });
.halfStyle { /* base char and also the bottom 1/3 */ position: relative; display: inline-block; font-size: 80px; /* or any font size will work */ color: transparent; overflow: hidden; white-space: pre; /* to preserve the spaces from collapsing */ color: #f0f; text-shadow: 2px 2px 0px #0af; /* for demo purposes */ } .halfStyle:before { /* creates the top 1/3 */ display: block; z-index: 2; position: absolute; top: 0; height: 33.33%; content: attr(data-content); /* dynamic content for the pseudo element */ overflow: hidden; pointer-events: none; /* so the base char is selectable by mouse */ color: #f00; /* for demo purposes */ text-shadow: 2px -2px 0px #fa0; /* for demo purposes */ } .halfStyle:after { /* creates the middle 1/3 */ display: block; position: absolute; z-index: 1; top: 0; height: 66.66%; content: attr(data-content); /* dynamic content for the pseudo element */ overflow: hidden; pointer-events: none; /* so the base char is selectable by mouse */ color: #000; /* for demo purposes */ text-shadow: 2px 2px 0px #af0; /* for demo purposes */ }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script> <p>Single Characters:</p> <span class="halfStyle" data-content="X">X</span> <span class="halfStyle" data-content="Y">Y</span> <span class="halfStyle" data-content="Z">Z</span> <span class="halfStyle" data-content="A">A</span> <hr/> <p>Automated:</p> <span class="textToHalfStyle">Half-style, please.</span>
(JSFiddle demo)
// jQuery for automated mode jQuery(function($) { var text, chars, $el, i, output; // Iterate over all class occurences $('.textToHalfStyle').each(function(idx, el) { $el = $(el); text = $el.text(); chars = text.split(''); // Set the screen-reader text $el.html('<span style="position: absolute !important;clip: rect(1px 1px 1px 1px);clip: rect(1px, 1px, 1px, 1px);">' + text + '</span>'); // Reset output for appending output = ''; // Iterate over all chars in the text for (i = 0; i < chars.length; i++) { // Create a styled element for each character and append to container output += '<span aria-hidden="true" class="halfStyle" data-content="' + chars[i] + '">' + chars[i] + '</span>'; } // Write to DOM only once $el.append(output); }); });
body { background-color: black; } .textToHalfStyle { display: block; margin: 200px 0 0 0; text-align: center; } .halfStyle { font-family: 'Libre Baskerville', serif; position: relative; display: inline-block; width: 1; font-size: 70px; color: black; overflow: hidden; white-space: pre; text-shadow: 1px 2px 0 white; } .halfStyle:before { display: block; z-index: 1; position: absolute; top: 0; width: 50%; content: attr(data-content); /* dynamic content for the pseudo element */ overflow: hidden; color: white; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script> <p>Single Characters:</p> <span class="halfStyle" data-content="X">X</span> <span class="halfStyle" data-content="Y">Y</span> <span class="halfStyle" data-content="Z">Z</span> <span class="halfStyle" data-content="A">A</span> <hr/> <p>Automated:</p> <span class="textToHalfStyle">Half-style, please.</span>
(JSFiddle demo)
// jQuery for automated mode jQuery(function($) { var text, chars, $el, i, output; // Iterate over all class occurences $('.textToHalfStyle').each(function(idx, el) { $el = $(el); text = $el.text(); chars = text.split(''); // Set the screen-reader text $el.html('<span style="position: absolute !important;clip: rect(1px 1px 1px 1px);clip: rect(1px, 1px, 1px, 1px);">' + text + '</span>'); // Reset output for appending output = ''; // Iterate over all chars in the text for (i = 0; i < chars.length; i++) { // Create a styled element for each character and append to container output += '<span aria-hidden="true" class="halfStyle" data-content="' + chars[i] + '">' + chars[i] + '</span>'; } // Write to DOM only once $el.append(output); }); });
.halfStyle { position: relative; display: inline-block; font-size: 68px; color: rgba(0, 0, 0, 0.8); overflow: hidden; white-space: pre; transform: rotate(4deg); text-shadow: 2px 1px 3px rgba(0, 0, 0, 0.3); } .halfStyle:before { /* creates the left part */ display: block; z-index: 1; position: absolute; top: -0.5px; left: -3px; width: 100%; content: attr(data-content); overflow: hidden; pointer-events: none; color: #FFF; transform: rotate(-4deg); text-shadow: 0px 0px 1px #000; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script> <p>Single Characters:</p> <span class="halfStyle" data-content="X">X</span> <span class="halfStyle" data-content="Y">Y</span> <span class="halfStyle" data-content="Z">Z</span> <span class="halfStyle" data-content="A">A</span> <hr/> <p>Automated:</p> <span class="textToHalfStyle">Half-style, please.</span>
(JSFiddle demo and on samtremaine.co.uk)
Customized different Half-Style style-sets can be used on desired elements on the same page. You can define multiple style-sets and tell the plugin which one to use.
The plugin uses data attribute data-halfstyle="[-CustomClassName-]"
on the target .textToHalfStyle
elements and makes all the necessary changes automatically.
So, simply on the element containing the text add textToHalfStyle
class and data attribute data-halfstyle="[-CustomClassName-]"
. The plugin will do the rest of the job.
Also the CSS style-sets' class definitions match the [-CustomClassName-]
part mentioned above and is chained to .halfStyle
, so we will have .halfStyle.[-CustomClassName-]
jQuery(function($) { var halfstyle_text, halfstyle_chars, $halfstyle_el, halfstyle_i, halfstyle_output, halfstyle_style; // Iterate over all class occurrences $('.textToHalfStyle').each(function(idx, halfstyle_el) { $halfstyle_el = $(halfstyle_el); halfstyle_style = $halfstyle_el.data('halfstyle') || 'hs-base'; halfstyle_text = $halfstyle_el.text(); halfstyle_chars = halfstyle_text.split(''); // Set the screen-reader text $halfstyle_el.html('<span style="position: absolute !important;clip: rect(1px 1px 1px 1px);clip: rect(1px, 1px, 1px, 1px);">' + halfstyle_text + '</span>'); // Reset output for appending halfstyle_output = ''; // Iterate over all chars in the text for (halfstyle_i = 0; halfstyle_i < halfstyle_chars.length; halfstyle_i++) { // Create a styled element for each character and append to container halfstyle_output += '<span aria-hidden="true" class="halfStyle ' + halfstyle_style + '" data-content="' + halfstyle_chars[halfstyle_i] + '">' + halfstyle_chars[halfstyle_i] + '</span>'; } // Write to DOM only once $halfstyle_el.append(halfstyle_output); }); });
/* start half-style hs-base */ .halfStyle.hs-base { position: relative; display: inline-block; font-size: 80px; /* or any font size will work */ overflow: hidden; white-space: pre; /* to preserve the spaces from collapsing */ color: #000; /* for demo purposes */ } .halfStyle.hs-base:before { display: block; z-index: 1; position: absolute; top: 0; width: 50%; content: attr(data-content); /* dynamic content for the pseudo element */ pointer-events: none; /* so the base char is selectable by mouse */ overflow: hidden; color: #f00; /* for demo purposes */ } /* end half-style hs-base */ /* start half-style hs-horizontal-third */ .halfStyle.hs-horizontal-third { /* base char and also the bottom 1/3 */ position: relative; display: inline-block; font-size: 80px; /* or any font size will work */ color: transparent; overflow: hidden; white-space: pre; /* to preserve the spaces from collapsing */ color: #f0f; text-shadow: 2px 2px 0px #0af; /* for demo purposes */ } .halfStyle.hs-horizontal-third:before { /* creates the top 1/3 */ display: block; z-index: 2; position: absolute; top: 0; height: 33.33%; content: attr(data-content); /* dynamic content for the pseudo element */ overflow: hidden; pointer-events: none; /* so the base char is selectable by mouse */ color: #f00; /* for demo purposes */ text-shadow: 2px -2px 0px #fa0; /* for demo purposes */ } .halfStyle.hs-horizontal-third:after { /* creates the middle 1/3 */ display: block; position: absolute; z-index: 1; top: 0; height: 66.66%; content: attr(data-content); /* dynamic content for the pseudo element */ overflow: hidden; pointer-events: none; /* so the base char is selectable by mouse */ color: #000; /* for demo purposes */ text-shadow: 2px 2px 0px #af0; /* for demo purposes */ } /* end half-style hs-horizontal-third */ /* start half-style hs-PeelingStyle, by user SamTremaine on Stackoverflow.com */ .halfStyle.hs-PeelingStyle { position: relative; display: inline-block; font-size: 68px; color: rgba(0, 0, 0, 0.8); overflow: hidden; white-space: pre; transform: rotate(4deg); text-shadow: 2px 1px 3px rgba(0, 0, 0, 0.3); } .halfStyle.hs-PeelingStyle:before { /* creates the left part */ display: block; z-index: 1; position: absolute; top: -0.5px; left: -3px; width: 100%; content: attr(data-content); overflow: hidden; pointer-events: none; color: #FFF; transform: rotate(-4deg); text-shadow: 0px 0px 1px #000; } /* end half-style hs-PeelingStyle */ /* start half-style hs-KevinGranger, by user KevinGranger on StackOverflow.com*/ .textToHalfStyle.hs-KevinGranger { display: block; margin: 200px 0 0 0; text-align: center; } .halfStyle.hs-KevinGranger { font-family: 'Libre Baskerville', serif; position: relative; display: inline-block; width: 1; font-size: 70px; color: black; overflow: hidden; white-space: pre; text-shadow: 1px 2px 0 white; } .halfStyle.hs-KevinGranger:before { display: block; z-index: 1; position: absolute; top: 0; width: 50%; content: attr(data-content); /* dynamic content for the pseudo element */ overflow: hidden; color: white; } /* end half-style hs-KevinGranger
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script> <p> <span class="textToHalfStyle" data-halfstyle="hs-base">Half-style, please.</span> </p> <p> <span class="textToHalfStyle" data-halfstyle="hs-horizontal-third">Half-style, please.</span> </p> <p> <span class="textToHalfStyle" data-halfstyle="hs-PeelingStyle">Half-style, please.</span> </p> <p style="background-color:#000;"> <span class="textToHalfStyle" data-halfstyle="hs-KevinGranger">Half-style, please.</span> </p>
(JSFiddle demo)
I've just finished developing the plugin and it is available for everyone to use! Hope you will enjoy it.
First of all, make sure you have the jQuery
library is included. The best way to get the latest jQuery version is to update your head tag with:
<script src="http://code.jquery.com/jquery-latest.min.js"></script>
After downloading the files, make sure you include them in your project:
<link rel="stylesheet" type="text/css" href="css/splitchar.css"> <script type="text/javascript" src="js/splitchar.js"></script>
All you have to do is to asign the class splitchar
, followed by the desired style to the element wrapping your text. e.g
<h1 class="splitchar horizontal">Splitchar</h1>
After all this is done, just make sure you call the jQuery function in your document ready file like this:
$(".splitchar").splitchar();
In order to make the text look exactly as you want it to, all you have to do is apply your design like this:
.horizontal { /* Base CSS - e.g font-size */ } .horizontal:before { /* CSS for the left half */ } .horizontal:after { /* CSS for the right half */ }
That's it! Now you have the Splitchar
plugin all set. More info about it at http://razvanbalosin.com/Splitchar.js/.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With