matt laine dot com / blog

Author Archive

[UPDATE] CSS text truncation with ellipsis…

by on Nov.09, 2010, under CSS, Firefox, web development, WebKit

Just an update…I’ve been getting a few comments on this and seems like the FireFox hack mentioned in the previous post will not work in FireFox4.

I did a quick check and it looks like they removed support for -moz-binding declarations in the CSS. This was probably for security reasons. See https://bugzilla.mozilla.org/show_bug.cgi?id=546857 and https://bugzilla.mozilla.org/show_bug.cgi?id=312156 for more information.

Until Firefox adds support for this, use with caution (or use WebKit).

1 Comment : more...

CSS text truncation with ellipsis…

by on Feb.12, 2010, under CSS, Firefox, web development, WebKit

I have been working on a project for several months now, that has a reoccurring feature for just about every line of text; the text truncates with an ellipsis (“…”). Why truncate your text when you can just let your text wrap naturally? There are several reasons why you might not want your text to wrap:

  • the size of the text (number of characters) is unknown
  • the text will get localized into several languages
  • the text might have a container with a fluid height or width
  • a page has to be compatible on mobile devices, multiple platforms

text-overflow: ellipsis;

The most obvious way to do this is to use the CSS rule text-overflow: ellipsis;. This will automatically clip your text depending on the size of the container, and apply “…”. A few important things to note are the white-space:nowrap and overflow:hidden must be in effect. Also, the element must either be a block-element (like DIV, P, or UL) or inline-block (if the browser supports it).

Here is an example:

<style type="text/css">

.truncate {
  white-space: nowrap;
  text-overflow: ellipsis;
  overflow: hidden;
}
</style>

<div class="container">
  <p class="truncate">Hi, I'm a really long line of text
that is going to get truncated by my 200 pixel wide parent element</p>
</div>

Hi, I’m a really long line of text that is going to get truncated by my 200 pixel wide parent element.

Text-overflow is supported on Internet Explorer and WebKit (Opera supports it’s own -o-text-overflow). If you are browsing in Firefox, you’ll notice that there is no ellipsis.

Works for IE6 but not Firefox?

Because, according to the Mozilla Developer Center text-overflow has no W3C specification, Firefox does not support this property. This has been a bug for a long time, and there is no indication on when Firefox support might become available.

Hacking Support in Firefox

What happens when browsers don’t behave the way we want? We hack.

The only working hack I’ve found is the same one discussed here and here, and basically using a XBL binding in CSS with the Firefox supported -moz-binding property. The CSS is bound to a XUL document and tells the element(s) to tail truncate, which by default applies an ellipsis.

XUL file (ellipsis.xml):

<?xml version="1.0"?>
<bindings 
  xmlns="http://www.mozilla.org/xbl"
  xmlns:xbl="http://www.mozilla.org/xbl"
  xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
>
	<binding id="ellipsis">
		<content>
			<xul:window>
				<xul:description crop="end" xbl:inherits="value=xbl:text"><children/></xul:description>
			</xul:window>
		</content>
	</binding>
</bindings>

And so in our CSS we’ll have:

<style type="text/css">
.truncate {
  white-space: nowrap;
  text-overflow: ellipsis;
  overflow: hidden;
  -moz-binding: url(ellipsis.xml#ellipsis);
}
</style>

Hi, I’m a really long line of text that is going to get truncated by my 200 pixel wide parent element.

Cross-browser Caveats

I found out the hard way that there are several caveats to using the Firefox XUL/XBL hack:

  • the ellipsis.xml file (and CSS file) must be on the same domain as the webpage! This means that if you are going to source to and external server for these assets, Firefox will not display properly
  • your text may no longer be selectable.
  • line-height may be ignored

Also, the CSS must select the element that is truncating; the style will not cascade down into other elements if there are siblings that are block-elements (like div, p, or ul);

<style type="text/css">
.truncate {
  width: 100px;
  white-space: nowrap;
  text-overflow: ellipsis;
  overflow: hidden;
  -moz-binding: url(ellipsis.xml#ellipsis);
}
</style>

<div class="truncate">
  Blah, blah, blah. I will not truncate!!
  <p class="truncate">Yessir! I truncate looooooong time!!</p>
</div>
Blah, blah, blah. I will not truncate!!

Yessir! I truncate looooooong time!!

10 Comments more...

New Twitter Mashup, Celebirdies.com

by on Aug.17, 2009, under api, twitter, web development

Announcing a new venture that I call Celebirdies. Celebirdies are actors, musicians and personalities, otherwise know as celebrities, that use social media like Twitter and TwitPic. Celebirdies.com brings celebrity tweets and twitpics into one easy to navigate site.

Celebirdies was built and designed by yours truly. It has a weekly featured celeb, as well as profiles on 350+ celebs. The site has been in development for 3-4 months, but new features will be added on a ad hoc basis. Currently you can search or browse from A-Z to find your favorite celebs. There is also the ability to social-bookmark the site and/or post to Twitter and Facebook. Future development will include support for different types of media, celebrity categories, comments, and up/down voting.

I’m going to be posting a series of articles related to the development of Celebirdies from concept to launch. Please take a chance to check out my site, and follow @celebirdies for the latest. Let me know what you think!

Leave a Comment : more...

HTML 5 and WebKit

by on Jun.23, 2009, under Uncategorized

It’s been awhile since I’ve blogged, so I thought I’d write about some HTML 5 studies I’ve been experimenting with. Check out the demo in Safari 4

In the example, I’m using King Kong to demonstrate several new features of the HTML 5 specification, such as the <video> tag, as well as some very cool WebKit CSS animations.

WebKit is the open source project with backing from Apple. Apple’s Safari and Mobile Safari browsers run on WebKit. You can think of WebKit as where the chrome (address bar, etc.) ends and the content begins; basically it’s everything in the viewport. Google Chrome and other browsers also run on a WebKit core.

Animations and Keyframes

As a UI developer, HTML 5 is a gift from God. Traditionally, developers would use images, Javascript or flash to accomplish what HTML 5 and CSS 3 can do with a few simple lines of code. WebKit has fully embraced the HTML 5 spec, which is still under development, and added it’s own set of CSS transforms, transitions and animations to further enrich the user experience. Let’s look at some code from the example:


/* this CSS controls the spotlights at the base of the building */
ul li.light1 {
        -webkit-transform-origin: bottom;
        -webkit-animation-name:'lightsrc1';
        -webkit-animation-duration:5s;
        -webkit-animation-iteration-count:infinite;
}

ul li.light2 {
        -webkit-transform-origin: bottom;
        -webkit-animation-name: 'lightsrc2';
        -webkit-animation-duration:5s;
        -webkit-animation-iteration-count:infinite;
}

Here I’m using a transparent .png background image as the spotlight. I positioned the lights at the base of the building and am using animations called ‘lightsrc1’ and ‘lightsrc2’ for each light respectively. The animations themselves look like this:


/* animations */
@-webkit-keyframes 'lightsrc1' {
	0% {
		-webkit-transform: rotate(0deg);
	}
	25% {
		-webkit-transform: rotate(-15deg);
	}
	50% {
		-webkit-transform: rotate(15deg);
	}
	75% {
		-webkit-transform: rotate(-15deg);
	}
	100% {
		-webkit-transform: rotate(0deg);
	}
}
@-webkit-keyframes 'lightsrc2' {
	0% {
		-webkit-transform: rotate(-15deg);
	}
	25% {
		-webkit-transform: rotate(15deg);
	}
	50% {
		-webkit-transform: rotate(0deg);
	}
	75% {
		-webkit-transform: rotate(15deg);
	}
	100% {
		-webkit-transform: rotate(-15deg);
	}
}

I’m using CSS keyframes to set the properties at certain intervals of the animation. As you can see, I’m setting -webkit-transform:rotate(# degrees) for each frame. This creates a pretty smooth transition between states. I’m also using keyframes to animate King Kong and the airplanes flying overhead; King Kong is also using the ‘rotate’ property on his arm. The planes are using ‘scale’ to fake a near-to-far effect. Here is that animation:


/* Plane A and Plane B CSS */
div.planeA,
div.planeB {
        -webkit-transition:-webkit-transform 4s linear;
        -webkit-animation-duration:4s;
        -webkit-animation-iteration-count:infinite;
}

div.planeA {
        background-image:url('planeA.png');
        -webkit-animation-name: 'planecircleA';
        z-index:4;
}

div.planeB {
        top:50px;
        left:-200px;
        background-image:url('planeB.png');
        -webkit-animation-name: 'planecircleB';
        z-index:0;
        -webkit-animation-delay:2.8s;
}

/* animations */
@-webkit-keyframes 'planecircleA' {
	0% {
		top:-40px;
		left:300px;
		-webkit-transform: scale(1.0, 1.0);
	}

	100% {
		top:50px;
		left:-100px;
		-webkit-transform: scale(0.1, 0.1);
	}
}
@-webkit-keyframes 'planecircleB' {
	0% {
		top:50px;
		left:-100px;
		-webkit-transform: scale(0.1, 0.1);
	}

	100% {
		top:-40px;
		left:300px;
		-webkit-transform: scale(1.0, 1.0);
	}
}

Once again, I’m using the keyframes to control the CSS transformations. I was attempting to make the planes look like 1 plane flying in a circle, but failed (albeit gracefully). Notice the property on planeB for -webkit-animation-delay, which delays the start of the animation.

HTML 5 Video

Probably one of the most exciting features of HTML 5 is the <video> tag. This allows the browser to play video in a variety of formats without requiring plugins (such as Flash). The can open up a whole new dimension in building rich applications in HTML/CSS and Javascript. The demo video is a .mov file and uses Javascript for the play/pause and full-screen functions.

Here is some CSS (I’m only including the -webkit* related properties):


/* this is the CSS for the video controls */
div.controls a { 
	background: -webkit-gradient(linear, left top, left bottom, from(rgb(22,22,22)), to(rgb(66,66,66)));;
	-webkit-border-radius:4px; 
	-webkit-transition: -webkit-transform 0.1s ease-in;
}

div.controls a:hover {
	-webkit-transform: scale(1.2, 1.2);
	-webkit-box-shadow: 1px 1px 5px rgba(255, 255, 255, 0.6);
}

/* this is the CSS for the video */
video { 
	background:(22,22,22,0.5); -webkit-box-reflect:below 1px -webkit-gradient(linear, left top, left bottom, from(transparent), color-stop(0.85, transparent), to(white));  
	-webkit-transition: -webkit-transform 1s ease-in; 
}

video.fullscreen { 
	-webkit-transform-origin: top left; 
	-webkit-animation-name: 'fullscreen'; 
	-webkit-animation-duration:1s; 
}
video.normal { 
	-webkit-transform: scale(1.0, 1.0); 
}

…HTML…


<div class="controls">
	<a href="#" class="play" onclick="toggle(this)">play</a>
	<a href="#" class="fullscreen" onclick="fullscreen(this)">fullscreen</a>
</div>

…and the Javascript:


//this function handles the play/pause actions
var toggle = function(obj){
	if(obj.innerHTML == 'play'){
		obj.innerHTML = 'pause';
		document.getElementsByTagName('video')[0].play();

	} else {
		obj.innerHTML = 'play';
		document.getElementsByTagName('video')[0].pause();
	}
}

//this function handles the fullscreen/normal views
var fullscreen = function(obj){
	var video = document.getElementsByTagName('video')[0];
	try { console.log(video); } catch(e) { alert(video); }
	video.className = video.className == 'fullscreen'?'normal':'fullscreen';
	obj.innerHTML = obj.innerHTML == 'fullscreen'?'normal':'fullscreen';
}

What I found is that HTML 5 and WebKit allows developers to write less Javascript and more CSS. In fact, the Javascript becomes limited to toggling classnames, such as what happens in fullscreen and normal video views.

Anyways, all in all, WebKit seems to be pushing the RIA experience into the HTML 5 standard, which is a beautiful thing. If only other browsers (ahem..IE) could follow suit. But that’s a whole other rant…

1 Comment more...

Using Python and Shell to Manipulate Large Data

by on Apr.03, 2009, under python, shell scripting, web development

I’ve been working on a project where we are dealing with a large amount of data. So large in fact that it will crash most programs that try and open it (try parsing a 60MB CSV file with Excel). So, I’m using Mac OS X Terminal to read and sort through data using UNIX commands.

Often times, as a web developer, you are asked to step outside of your normal routine and do some investigating. In my case, I was asked to audit a website with over 30,000 pages. Simply figuring out how many pages were on the site was a large task on it’s own.

Getting a “complete” set of URLs

I say “complete” in quotes because for some sites it’s just not feasible to find 100% of the pages. The good thing is that a site that is really large will have a lot of stuff that the CEO or whoever just doesn’t care about. Still I wanted to capture as much data as I can as my starting point.

First, I used Xenu link sleuth to crawl the site for links. This is not the best way to crawl a site, but it was a quick way to get my set of URLs. On reason why this method isn’t the best is that it fails to find orphaned pages (pages that are not linked to by other pages). However, I does record some interesting tidbits about each page, such as the content-type, folder level relative to the site root, and whether or not the link was broken (404) or forbidden (403).

Bash that data into submission

After exporting this data out, my file was quick large. Since the data was in tab-delimited format, I knew I could extract the URLs by parsing the string after the first tab character. I use the awk program to do this.

$ awk -F"\t" 'OFS="\t"{print $1 >> url_results.txt}' url.txt

Next I wanted to filter out any duplicates. I do this by using sort with -u and -f flags. This basically tells the sort to treat uppercase and lowercase strings equally, and save the unique lines in a seperate text file

$ sort -u -f url_results.txt > url_results_uniq.txt

Enter the Python

Now my URL list is more manageable and I can play around with it. One thing that I wanted to do is see what the HTML source was for each file. This way, I can check to see what CSS files are linking from it, etc. Enter Python; a scripting language that also acts like an interpretor. It’s fast for processing large files and forces you to handle errors like 404s or page timeouts. Using Regular Expressions (again) to match the CSS file reference, my Python script goes a little like this:

#/bin/usr/python
import re, urllib2, socket
socket.setdefaulttimeout(10) ##this sets the timeout manually for each page


def analyzeData(url, htmlcode): ##this function does the regex matching
    patterns = dict(firststyle= '/pattern1.css/', secondstyle='/pattern2.css')
    for template in patterns:
        regex = str(patterns[template])
        if(re.search(regex, htmlcode)):
        #open file w/ template name, print url to it
            fh = "fileHandle"+template
            fh = open(template+".txt", "a")
            fh.write(url+'\n')
            print url+", "+template


f = open('urls_results_uniq.txt', 'r') ##opens the list of unique urls
httperror = open('httperror.txt', 'w') ##open/create a file to store HTTP errors
timeouts = open('timeouts.txt', 'w') ##open/create a file to store time outs
index = 0;
for line in f.readlines():
    urlregex = re.match('(^http:\/\/.*\.html|^http:\/\/.*\.php)', line) ##checks for .html or .php in url path (excludes images, css, etc.)
    if(urlregex):
        url = urlregex.group(1)
        try:
            req = urllib2.Request(url)
            page = urllib2.urlopen(req)
            htmlcode = page.read(1500)
            page.close()
            analyzeData(url, htmlcode);
        except urllib2.HTTPError: ##handle exceptions
            httperror.write(url+'\n')
            print str(index)+' - http error for '+url
        except urllib2.URLError:
            timeouts.write(url+'\n')
            print str(index)+' - url error (timeout) for '+url
        index = index + 1
f.close()
httperror.close()
timeouts.close()

The first part of the script imports the proper libraries. For the example, I’m using the Regular Expression library (re), urllib2 to send an HTTP request and return the HTML source, and socket to set the time out for each page manually. The second part is the function that actually does the regex matching on the html source code. I found out that the function had to be defined before it was called, which is different that what I’m used to in PHP. Lastly, I’m opening, reading, and looping through my list of URLs and calling the ‘analyzeData’ for each URL. If the function finds a match in the HTML source, it writes that to a file named either ‘firststyle’ or ‘secondstyle’.

My first impressions on Python

This was the first time I used Python. I’d previously tried to perform the method above using PHP and cURL. The script was continually timing out or stalling, so I changed technology. I also looked to see if I could leverage a Python framework for the task I was doing, such as Django, but for what I needed, I ended up using straight-up Python. Python is extremely fast, and I like the combination of using Python in the Shell. I also found it useful to print out something for each URL that I’m checking, that way I can know that the script is still running, even if no matches were found or an error was found.

Probably the hardest thing to get used to in Python is indenting the code. You have to indent properly or Python will not be able to interpret your code. I imagine this is an attempt to get rid of curly-braces, a la C or PHP, and to it’s credit, does force you to write code consistently. The down-side to using Python is that it’s a pretty big learning curve. I’m the type of person who won’t dive into something like Python with a project, or reason (other than curiosity).

Leave a Comment : more...

Domlets – bookmarks gone wild

by on Jan.23, 2009, under web development

Javascript bookmarklets have been around for quiet some time. In fact, most of the posts on bookmarklets.com are from the Netscape days. That said, I’d like to introduce a new way of looking at javascript bookmarks that I’m calling “domlets”

What’s a Domlet?

Domlet is a blend of DOM (or the Document Object Model that comprises a webpage) and bookmarklets (or favlets if you an IE-user). Domlets are used to manipulate the DOM using javascript to frame in a new content window.

Here is an example domlet for digg.com.

Another for twitter.com.

Domlets have only been tested on FireFox on Mac and Windows, and Safari on Mac. I’m hoping to have a version worked out for IE in the next few weeks.

How it works

Now for some technical stuff: the realization that you can execute javacript via the location or address bar was what lead me down the path of developing domlets. Web developers are usually well versed in bookmarklet tools like Visual Element which allows you to inspect the DOM for javascript events. Other sites like ma.gnolia.com incorporate use a bookmarket UI for social bookmarking, in that, any given page you are on, you can click the bookmarklet to view community comments or conversations related to that page.

What these scripts have in common is that they use the initial javascript to attach a script to the document.body node. Once attached, the script calls the function to initialize the script and perform whatever DOM-magic ensues. Domlets has a similar initialization approach. I also found that I had better success with my bookmark code if I attached the script using a self-executing function like this:

javascript:(function(){…script sniffed and attached here…})();

Also, I decided to use an object literal ‘Domlet’ to encapsulate my function names, thus avoiding any namespace issues I might have with scripts already loaded in the DOM. Here is the basic skeleton of a domlet:

var Domlet = {
defaults,
init : function(){},
addFrame :function(){}
}
…more functions here for animation and closing the frame
Domlet.init()

Lastly, I debated over whether or not to utilize a Javascript library for the domlet, but ended up not using a library and wrote everything myself (hence all the cross-browser bugs!). Had I used a library, I would have used JQuery, since the ‘min’ library is very light and I could easily implement it to create the same effects. In fact, this project was mainly inspired by the JQuery page-slide plugin, which uses a similar method of “wrapping” the page content and “throwing” it to the side to reveal a new content window.

Mobile Content Works Best

In formatting a domlet, I’ve chosen to capitalize on the growing number of mobile micro sites that are optimized for less than 320 pixels wide. There are several reasons for doing this; one is that I can simply iframe in the address of the micro site, like m.digg.com and m.twitter.com for the examples above. Another reason is to enable users to browse content formatted for mobile phones using their regular browser. I call this behavior “micro-browsing”. Often times, I just want to peek at my gmail or update my facebook status, but without opening up a new tab or leaving the page (pretty lazy, huh?). With domlets, I can simply load these micro-sites in a new pane and close it when I’m done.

As the web goes mobile in the next coming months, developers and users should establish standards for thinks like view-portal dimensions and CSS media types. What will be interesting is if/when developers and users decided on a standard, will micro-browsing really takes off as a behavior? Regardless, I hope that in developing domlets, I can encourage the development of a standard, i.e. one that works on your mobile and that domlets can render in your normal browser. Already, I think there are some 50+ mobile browsers, so settling on a standard will become increasingly difficult with time.

3 Comments :, , , more...

First, there was the post

by on Jan.20, 2009, under Uncategorized

Then there was the blog

Hi, there. Installed wordpress on my site so that i can easily write documentation for the projects i’m working on. Honestly, the hardest part about installing WP is choosing a theme!

Just for kicks, here is a little playlist for ya.

Leave a Comment : more...

Looking for something?

Use the form below to search the site:

Still not finding what you're looking for? Drop a comment on a post or contact us so we can take care of it!

Visit our friends!

A few highly recommended friends...

Archives

All entries, chronologically...