Tag Archives: CSS

React.js components with embedded styles

You have probably already seen global CSS files with thousands of lines that may influence anything. Change is too dangerous so you just add new rules. To the point everything must be rewritten.

I love React’s ability to build reusable components. Write once, put anywhere you like. This rule does not apply just for JavaScript, it may apply for CSS too. Did you know that you can use post-css with autoprefixer to autoprefix rules from CSS/SASS/LESS file? So every require of such file prepares class names that does not clash with anything else (like style__item___3dKqL).

That way you can prepare components that contains embedded styles that applies only for them. No complex CSS selectors are required – just use plain names:

embedcss

At the same time you can import application wide constants using SASS so you do not lose ability to set colors, sizes, … in single place.

Usage in code is simple:

code

(btw. to avoid join operation you can use classnames lib)

text-overflow: ellipsis from left

Today I needed to put one line of possibly long text into table. So text may be wider than table cell. In that case client needs to see end of that text because it contains more important data. What is worse my cell width depends on client resolution so I cannot trim text on server. Here is simple illustration:

 

overflow

There is CSS text-overflow property that can end text that can visualize by ellipsis (“…”) that text is longer than element size so it overflows element and is hidden. That is fine for text has more important part on the beginning. But what about text that has more important part on the end? It would be better to show ellipsis on left side, right?

Unfortunately it is not possible nowadays, there is only outdated draft of such function done by W3C. It would allow you to define behavior for both sides of text.

Other possibility are various CSS hacks, like this one, or this one, or … They are based on nasty tricks and suffer for many problems. One is common to all of them – they are using clipping by rectangle so text which is on border is clipped too. For example it cuts letter O so it looks like bracket. That is confusing, so this way was not feasible for me. See first example on image above.

So there is only one option. Yes, JavaScript :-/ My sample is using JQuery and works like this:

  1. Adds hidden element whose width is same as maximal text width into page
  2. Walks through all elements that may possibly overflow
  3. Put text (stored in data- attribute) that should be displayed into hidden element
  4. Shorten it by one letter as long as text is longer than hidden element
  5. Put shortened text into target element
  6. Possibly react on resize/ready/… events

Here is the code (download from github):

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>Left text-overflow test page</title>
		<script src="https://code.jquery.com/jquery-1.12.0.min.js"></script>

		<script>
		    //on document ready
			$(document).ready(function() {
	            shortenTexts();
            });

            //on widow resize
            $(window).resize(function() {
	            shortenTextsDelayed();
            });

            //wait for rendering done
            function shortenTextsDelayed() {
	            window.setTimeout(shortenTexts, 100);
            }

            function shortenTexts() {
	            //get ruler
	            var measureBox = $("#ruler");
	            var measureBoxSpan = measureBox.children("span").first();
	
	            //iterate over texts that should be shortened
	            $("div.shorten").each(function(index, element){
	                //target span
		            var span = $(element).children("span").first();
		            
		            //full text
		            var text = $(element).data("original");
		
		            //init by full text
		            measureBoxSpan.text(text);
		
		            //while span in ruler is bigger than ruler
		            while (text.length>0 && measureBoxSpan.width()>measureBox.width()) {
		                //shorten string
			            text = text.substring(1);
			
			            //set new text
			            measureBoxSpan.text("…"+text);
		            }
		
		            //set target text by succeeded text
		            span.text(measureBoxSpan.text());
	            });
            }
		</script>

		<style>
		    body {
		        padding: 0px;
		        margin: 0px;
		    }
		
		    body > div {
		        max-width: 90%;
		    
		        font-size: 25px;
		        overflow: hidden;
		        white-space: nowrap;
		        
		        border: 1px solid gray;
		        
		        padding: 5px;
		    }
		    
		    div.ellipsis {
		        text-overflow: ellipsis;
		    }
		    
		    #ruler {
		        position: absolute;
		        visibility: hidden;
		    }
		</style>
	</head>

	<body>
	    
	    <h1>Implicit</h1>	
		<div>
		    <span>
		        This is sooo long text. Probably it will overflow, right? 
		        But maybe, maybe there will be extremely important information 
		        that you should not miss in the end. Information that you 
		        should not miss. The ultimate answer. Curious? Now I will 
		        count 1 2 3 4 5 6 7 8 9. Really? I do not believe you! 
		        REALLY! So the ultimate answer is: 42!
		    </span>
		</div>
		
		<h1>text-overflow: ellipsis</h1>
		<div class="ellipsis">
		    <span>
		        This is sooo long text. Probably it will overflow, right? 
		        But maybe, maybe there will be extremely important information 
		        that you should not miss in the end. Information that you 
		        should not miss. The ultimate answer. Curious? Now I will 
		        count 1 2 3 4 5 6 7 8 9. Really? I do not believe you! 
		        REALLY! So the ultimate answer is: 42!
		    </span>
		</div>
		
		<h1>JavaScript shortening from left</h1>
		<div id="ruler"><span> </span></div>		
		<div class="shorten" data-original="This is sooo long text. Probably it will overflow, right? 
		        But maybe, maybe there will be extremely important information 
		        that you should not miss in the end. Information that you 
		        should not miss. The ultimate answer. Curious? Now I will 
		        count 1 2 3 4 5 6 7 8 9. Really? I do not believe you! 
		        REALLY! So the ultimate answer is: 42!">
		    <span> </span>
		</div>
	</body>

</html>

Result looks like, try to play with browser window size – overflow should adapt:
output

Enjoy!