Off The Top Of My Head

Shadowed text with CSS

Posted in Uncategorized by waltermilner on November 3, 2009

The target was to make a navigation bar like that at www.apple.com, which looks like this:

apple navbar

Apple navbar

They did this by having all the links share a single background image, with the x and y offsets for each set so they show the correct part of that single image. In turn the text shadowing has been done in the graphics package that made the image.

I wanted something like this that could be done using CSS, without having to handcraft a background image for each link. That’s what we’re trying to do.

Thanks to Krijn Hoetmer I had a JavaScript function which would shadow some text. But the first problem would be that I would need to put both a JavaScript link and a style sheet link in the HTML – I wanted just one link. After some Googling and experimenting I had some JS which would dynamically load a style sheet:

var cssNode = document.createElement(‘link’);
cssNode.type = ‘text/css’;
cssNode.rel = ’stylesheet’;
cssNode.href = ‘menuBar1.css’;
cssNode.media = ’screen’;
cssNode.title = ‘dynamicLoadedSheet’;
document.getElementsByTagName(“head”)[0].appendChild(cssNode);

So menuBar1.css would style the menu bar, and this JS would load it.

Next task is to shadow the text on eack link. This works by getting the div which encloses the menu, getting each of the child nodes, and calling the shadow function for each one:

var menu=document.getElementById(“menu”);
var children=menu.childNodes;
for (i=0; i<children.length; i++)
{
applyShadow(children[i], ‘white’, 3,10, 7);
}

The applyShadow function is originally by Krijn Hoetmer is modified here slightly, to handle text which has some padding (third and fourth parameters are teh left and top padding:

function applyShadow(targetElement, shadowColor, shadowOffset,pside, ptop) {
if (typeof(targetElement) != ‘object’) {
targetElement = document.getElementById(targetElement);
}
var value = targetElement.firstChild.nodeValue;
targetElement.style.position = ‘relative’;
targetElement.style.zIndex = 1;
var newEl = document.createElement(’span’);
newEl.appendChild(document.createTextNode(value));
newEl.className = ’shadowed’;
newEl.style.color = shadowColor;
newEl.style.position = ‘absolute’;
newEl.style.left = ‘0px’;
newEl.style.top = shadowOffset + ‘px’;
newEl.style.zIndex = -1;
newEl.style.paddingLeft=pside+1+”px”;
newEl.style.paddingTop=ptop+1+”px”;
targetElement.appendChild(newEl);

}

The HTML this is applying to is:

<div id=”menu”><a href=”nowhere” >Link One</a><a href=”nowhere”>Link Two</a><a href=”nowhere”>Link Three</a><a href=”nowhere”>Link Four</a></div>

This is all done in one line – any spaces or CRs produce spurious white space text nodes in the DOM tree.

This shadows the text – but we need to insert graphics for the link separators.  This is a rather bizarre loop:

var count = children.length;
for (i=0; i<count*2; i++)
{
var image = document.createElement(‘img’);
image.setAttribute(’src’,'images/gap.gif’);
menu.insertBefore(image,children[i]);
i++;
}

we go for twice the number of child nodes that are there – because when we’ve finished, we’ll have twice that number. And we go i++ every time we add one. children is dynamically updated as we add nodes.

The style sheet is

#menu
{
position: absolute;
left: 20%;
right: 20%;
min-width: 32%;
background-image: url(images/linkbg.gif);
-moz-border-radius: 5px;
text-align: center;
height: 37px;
}
#menu a
{
position:relative;
color: black;
font-family: arial, helvetica, sans-serif;
font-size:11px;
padding-left: 10px;
padding-top: 10px;
padding-bottom:10px;
top:-15px;
}

The background image is 37 pixels high. We’ll only get round corners in FF – that’s IE’s problem. The result is:

menu bar

My version

Works in FF and IE

 

JavaScript and OOP for the DOM

Posted in Uncategorized by waltermilner on August 30, 2009

I wanted a color transition effect on web page elements when the mouse cursor passed over them – like a:hover, but for any element, not just a link, and a transition over say 0.8 seconds, not just an abrupt change. onmouseout should transition to the original color of the element.

This can be done using onmouseover and onmouseout, but I wanted to set it up for elements of a given tag, class or id. So (after only 2 days) I did it using OOP in JavaScript – listing below. I define a class (strictly a prototype) called ColorP, which will have the behaviour I want, and associate some web page elements with instances of this class.   One tricky point is that the method to change the color has to be recursive, and it was difficult to find the syntax for this. Thanks to Pablo Cabrera for ‘arguments.callee’, which must be one of the obscurer backwaters of JavaScript.

The web page body is:

<p id=”test” style=”color: rgb(0,255,0);  background: #ff00ff” Hello</p>

<h1 id=”two” “>Goodbye</h1>

The body onload calls:

function start()
{
obj1 = new ColorP(“test”);
obj2=new ColorP(“two”);
return;
}

So 2 objects are created associated with these two elements. We could have traversed the document tree and done this for given tags or classes. The code for ColorP objects is:

function ColorP(id)
{
// data members ///////////////////////////////////////////
var obj;
// time in mS delay before each recursive call
var timeStep;
// initial colors
var red, green, blue;
// color change each step
var rDiff, gDiff, bDiff;
// current color
var red1, green1, blue1;
// target colours and time for transition
var r,g,b,time;
// count and count1 count the transition steps
var count, count1;

// two methods /////////////////////////////////////////////
this.fadeIn = function()
{
if (count==10) {
count=0;
return;
}
count++;
red1+=rDiff;
green1+=gDiff;
blue1+=bDiff;
// set colors to integer values
intR = Math.round(red1);
intG = Math.round(green1);
intB = Math.round(blue1);
obj.style.color=”rgb(“+intR+”,”+intG+”,”+intB+”)”;
setTimeout(arguments.callee, timeStep);
}

this.fadeBack = function()
{
if (count1==10) {
count1=0;
return;
}
count1++;
red1-=rDiff;
green1-=gDiff;
blue1-=bDiff;
// set colors to integer values
intR = Math.round(red1);
intG = Math.round(green1);
intB = Math.round(blue1);
obj.style.color=”rgb(“+intR+”,”+intG+”,”+intB+”)”;
setTimeout(arguments.callee, timeStep);
}

// cnstructor code ///////////////////////////////////////
r=255; // could be passed as constructor parameters
g=0;
b=45;
time=0.7;
// we will do this in 10 steps
// so time for each step = time * 100 milliseconds
timeStep = time*100;
count=0;
count1=0;
obj=document.getElementById(id);
// get colors
styles=obj.getAttribute(“style”);
cols=getColorFromStyles(styles);
if (cols==null) return; // do nothing if can’t obtain color’
// change to numbers
red=parseFloat(cols[0]);
green=parseFloat(cols[1]);
blue=parseFloat(cols[2]);
// work out colour change amounts
rDiff=(r-red)/10.0;
gDiff=(g-green)/10.0;
bDiff=(b-blue)/10.0;
// set current colors to the initial ones
red1=red;
green1=green;
blue1=blue;

obj.onmouseover=this.fadeIn;
obj.onmouseout=this.fadeBack;

}

Unfortunately the code to get the color style is different for IE:

// get foreground color from a set of style attributes
// this returns an array of 3 values – the rgb components
// it works for colors ONLY in the form rgb(a,b,c). If there
// are no styles, or no color defined, it returns
// the equivalent of black
function getColorFromStyles(styles)
{
// in IE, styles is a style object, and styles.color yields the color
// in FF and Opera, styles is a string like ‘color:rgb(1,2,3); background: rgb(4,5,6)’
c=styles.color;
if ( c == undefined ) // NOT IE, so get color:.. out of the string
{
if (styles==null)
return new Array(0,0,0);
// split on ; to separate attributes

pairs=styles.split(“;”);
// search for color
for (i=0; i<pairs.length; i++)
if (pairs[i].search(“color”)!=-1) break;
if (i==pairs.length) // no color..
return new Array(0,0,0);
// separate style from substance (!)
value=pairs[i].split(“:”);
// value[1] is rgb…
col=value[1].slice(5,value[1].length-1);
colours=col.split(“,”);
return colours;
}
else // for IE, so c is like ‘rgb(12,3,4)
{
if (c==”") // no color defined
return new Array(0,0,0);
col=c.slice(4,c.length-1); // slice from rgb(…
// split 3 parts on ,
colours=col.split(“,”);
return colours;
}

}

This works on FireFox, Opera and IE – maybe others

Tagged with: , , , , ,

Who hates JavaScript?

Posted in Uncategorized by waltermilner on May 17, 2008

Well, I don’t hate it when things are going well. But the biggest problem is that there is no standard with a precise documentation. OK well there is, only its called ECMAScript, and no implementation of JavaScript or JScript in any browser is compliant. Which is little use.

I wanted to make a page element flicker to draw attention to it. Looked obvious – just a loop with something like

thing = document.getElementById(id);
thing.style.color=”black”;

alternated with another colour, and maybe a delay. Easy.

Problem is browsers repaint the window only when script execution ends. You can’t force a repaint in the middle of a script. So you have to Google, and this always brings a mix of complete garbage, partial garbage and little hints.

The solution is setTimeout. This seems irrelevant – setTimeout(f,n) calls function f after n milliseconds. But the point is that it looks like script termination, and is followed by a re-paint. So the two colour settings are simply a pair of mutually recursive functions which call each other with setTimeout, and needed a decremented countdown to stop it going forever. In other words:

function flicker(id)
{// this is the initial call
flickred(id, 30);
}

function flickred(id, c)
{
if (c<0) return; //if we are still going..
thing = document.getElementById(id);
thing.style.color=”red”; // change colour
// call other after 0.1 secs with decremented counter..
setTimeout(“flickwhite(‘”+id+”‘,”+(c-1)+”)”, 100);
}

function flickwhite(id, c)
{
if (c<0) return;
thing = document.getElementById(id);
thing.style.color=”white”;
setTimeout(“flickred(‘”+id+”‘,”+(c-1)+”)”, 100);
}

Only wasted about 2 hours!!

My pretty pastel website

Posted in Uncategorized by waltermilner on March 14, 2008

I’ve hardly touched my website for around a year, but I’m currently preparing to teach a week-long course on HTML, CSS, JavaScript, SQL and PHP (pretty good in a week) so I thought I should practice what I preach. Which I can’t, really, because I’m visually pretty uncreative. But I know how to Google, and I found this excellent color scheme gismo, and this piece about web fonts, and the result is this. What do you think?

Tagged with: , , , , ,