Showing posts with label css. Show all posts
Showing posts with label css. Show all posts

Tuesday, 18 June 2013

Removing the iPhone navigation bar in 100% height layouts

Just a quicky - I've just finished a site that uses

#container {
    position: absolute;
    top: 0;
    left: 0;
    bottom: 0;
    right: 0;
    overflow: hidden;
}

to lock the site to an app-like, 100% x 100% layout (thanks Steven Sanderson). But when it came to the usual trick of

if(navigator.userAgent.toLowerCase().indexOf("iphone") !==-1) {
    window.scrollTo(0,1);
}

to remove the Safari navigation bar nothing happens! This is because, as the layout is only 100% tall, there's nowhere to scroll to. So a quick fix is to do this:

if(navigator.userAgent.toLowerCase().indexOf("iphone") !==-1) {
    $('body').height(screen.availHeight-44);
    window.scrollTo(0,1);
}

This (jQuery assumed) pushes the body out to fill the available height (minus 44px for the navigation bar). Then the scrollTo works perfectly.

Voila, app like layout.

Wednesday, 22 May 2013

Adding text strokes with jquery and css text shadows

Due to the fact that css text stroke is not widely supported I decided to roll own using jquery, CSS text shadows, and a little bit of trigonometry.

It's easy enough to do, because CSS allows you to apply multiple text shadows to an object. If you set the blur on these to zero, and place them evenly around your text, you get a stroke.

A single CSS text-shadow rule looks like

.classname {
    text-shadow: 1px 1px 2px #ff0000;
}

giving a 1px offset in each direction, a 2px blur and a nice red shadow (urgh).

Multiple shadows can simply be joined by commas, like so

.classname {
    text-shadow: 1px 1px 2px #ff0000, 0px 1px 3px #00ff00, 1px 3px 2px #ffff00;
}

(Don't try this at home kids, it'll look disgusting).

The trick here is working out where to put the stroke in relation to the text. I want a smooth stroke with rounded corners and caps (I might extend this to square caps, but not right now!), so I'm going to place my strokes in a circular pattern. Imagine a full stop/period, then add a stroke above, right and down a bit, right and down a bit, reach 3 o'clock, down and left a bit, down and left a bit, 6 o'clock etc.

But how to calculate exactly where to put these shadows?

This is easy with the parametric equation of the circle, which is:

x = r * cos(t)
y = r * sin(t)

Don't worry about the specifics of this equation, just trust me that X and Y are the number of pixels up or down put our shadow and r is the width of the shadow. The variable t just steps around our circle, from 0 to 2π (360°) and gives us the x and y position.

So, to the code.

First, this is a jQuery plugin, so we start with

$.fn.textStroke = function(r, colour) {

r is the radius in pixels and colour is a hex code, e.g. '#ff0000'

var rules = [];
var steps = 24;

I'm creating an array to add each CSS text-shadow rule to as we go around the circle, and I'm using 24 steps - this is purely subjective. 24 steps was necessary for a smooth stroke on a big header, but 12 will probably do for smaller text. Note I've gone for multiples of 4 so that each quadrant has the same number of text-shadows.

for (var t=0;t<=(2*Math.PI);t+=(2*Math.PI)/steps){

Here i'm looping through a full circle in radians (2π radians to 360°, kids!), in the number of steps set above.

var x = r*Math.cos(t);
var y = r*Math.sin(t);

Here we get our x and y values. And we're done for this step! Except we're not, because sometimes things break. Because we'll convert x and y to strings in a minute, we hit a problem when we get really really tiny but not quite zero numbers at certain points around the circle - numbers like 5.2485234e-013 (a very, very small number) aren't understood by CSS, so...

x = (Math.abs(x) < 1e-6) ? '0' : x.toString();
y = (Math.abs(y) < 1e-6) ? '0' : y.toString();

...if the number is less than one millionth, we set it to zero. And convert to strings here because I like messy code. Finally, we make a rule from these values and add it to the rules array...

rules.push( x + "px " + y + "px 0px " + colour );

and continue the loop...

Finally, we join the rules we've created and apply using the css function in jQuery.

this.css('textShadow',rules.join());

Note I haven't mentioned vendor-specific prefixes here - that's because, thankfully, jQuery generates them automatically.

And that's it!

$.fn.textStroke = function(r, colour) {
 
var rules = [];
var steps = 24;

for (var t=0;t<=(2*Math.PI);t+=(2*Math.PI)/steps){
 
var x = r*Math.cos(t);
var y = r*Math.sin(t);

x = (Math.abs(x) < 1e-6) ? '0' : x.toString();
y = (Math.abs(y) < 1e-6) ? '0' : y.toString();

rules.push( x + "px " + y + "px 0px " + colour );

}

this.css('textShadow',rules.join());

};

So, all we have to do to add a lovely text stroke to any element is to do

$('#thingtobestroked').textStroke(5, '#ffffff')

and we're done.

There's a jsfiddle demo at http://jsfiddle.net/KjyYV/ , and you can check out my crappy code at my GitHub repo. It's currently a mess and doesn't follow the jQuery boilerplate, because I'm lazy and hacked this together in ten minutes, but it'll improve!