Pages: << 1 ... 4 5 6 7 8 9 10 11 12 13 14 ... 32 >>

09/06/09

12:49:56 am, by delicious, 122 words, 2349 views   en-UK
Categories: Delicious

Links for September 6th


Tweet this!

09/04/09

12:38:03 am, by robertc Email , 822 words, 46508 views   en-UK
Categories: Front End Web Development, Standards, HTML and CSS

Arbitrary Element Rotation in IE - the Matrix Filter

There was a post on WebDesign-L today asking about angled text, which reminded me of the excellent Text Rotation with CSS a few months back on snook.ca. Jonathan focussed on the IE only BasicImage filter to provide an alternative to the (also proprietary but future standard) -webkit-transform and -moz-transform properties to rotate text. That's fine as far as it goes, but BasicImage can only rotate in increments of 90°. Jonathan mentions the alternative, the Matrix filter, but says "the coordinates still don't make any sense to me."

Now, WebKit and Gecko also support matrix transformations, so I'm thinking if I can only work out what the co-ordinates mean we might have the basis of a more general purpose solution. So I looked at the Wikipedia examples of linear transformation matrices and then the Mathamazement introduction linked to from the MDC page. If you can hear a loud whooshing sound right now, that's the echo of a load of math stuff flying completely over my head...

However, all was not lost - if we go back to the MSDN Matrix transform article you'll see there's some example code. With something to hack around I thought I had a much better chance of figuring out how things worked. I started off with the fourth sample, it uses Javascript to animate the Matrix transform, rotating and expanding a div element.

I modified the code a bit, but I'll take you through the key points before I show you what I finished up with. First of all, the Matrix transform needs to be defined on the element in question before you can script it:

<DIV ID="oDiv" STYLE="position:absolute;
filter:progid:DXImageTransform.Microsoft.Matrix(sizingMethod='auto expand')"
		onfilterchange="fnSpin(this)" >

The animation is powered by fnSpin which calls two subsidiary functions, fnResize to resize the image and fnSetRotation to rotate it. Here's the original code for the rotation:

//oObj input requires that a matrix filter be applied. 
//deg input defines the requested angle of rotation.
var deg2radians = Math.PI * 2 / 360;
function fnSetRotation(oObj, deg)
{    rad = deg * deg2radians ;
    costheta = Math.cos(rad);
    sintheta = Math.sin(rad);

    oObj.filters.item(0).M11 = costheta;
    oObj.filters.item(0).M12 = -sintheta;
    oObj.filters.item(0).M21 = sintheta;
    oObj.filters.item(0).M22 = costheta;

}

So here's it all nicely laid out with all the hard math stuff already done for us. The basic math stuff is it's converting the degrees into radians, then using sine and cosine functions to calculate the four matrix values. So now I'm thinking I can reverse engineer this function to work out what the matrix values will be for any angle. I started off with modifying the fnSetRotation so that the matrix values were visible on the page - adding four text inputs and these lines:

    document.getElementById("fM11").value = oObj.filters.item(0).M11;
    document.getElementById("fM12").value = oObj.filters.item(0).M12;
    document.getElementById("fM21").value = oObj.filters.item(0).M21;
    document.getElementById("fM22").value = oObj.filters.item(0).M22;

Then I added a button which rotates the element to 45° when clicked (warning, IE only):

Rotate element by 45 degrees in IE

The next step was to make the page work cross browser, accept a value for the input number of degrees and, for bonus credits, generate the relevant CSS for copy and pasting. First of all I cleaned up the output a bit with toFixed method as, when the values got close to zero, they end up in exponent format rather than just rounding to 0. This gave me numbers I could plug straight into a CSS template, for example here's the declaration to rotate an element by 45°:

filter: progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678);

So now I thought it would be a fairly straightforward task of plugging these values into the Mozilla format:

-moz-transform:  matrix(a, b, c, d, tx, ty)

The tx and ty are for translation, so I just set them to zero, then plugged M11, M12, M21 and M22 into a, b, c and d respectively. Unfortunately, it didn't work! The element was reflected in respect to IE in Firefox for certain rotations.

Someone who actually understands what's going on with the matrices could probably explain what's happening (probably I have the co-ordinate system the wrong way up?) but I fell back on trial and error and eventually decided that swapping b and c worked. See my final matrix calculator here - input an angle in degrees, click the button and see the CSS code for achieving it in IE, Gecko and WebKit.

Some things I noticed but didn't have time to investigate fully:

  • IE seems to rotate around the center, Firefox and Chrome seem to rotate from top left. There's a -moz-transform-origin and equivalent WebKit property to control things in those browsers, not sure what equivalents IE offers.
  • Other CSS declarations are applied after the transform in IE, while they seem to be applied before the transform in Firefox and Chrome (ie. if you add 200px padding to the top of an element, Firefox will rotate around a point 200px above the 'start' of the element, IE will apply 200px padding after the transform).
  • Using the rotate syntax in Gecko and WebKit is a lot simpler, but if you want to rotate stuff in IE too using a similar format in all three might be more simple in the long run? Especially if you want to script it.

Tweet this!

09/02/09

06:21:22 pm, by robertc Email , 366 words, 66648 views   en-UK
Categories: Front End Web Development, Standards, HTML and CSS

Rounded Corners for Image Elements in Firefox with SVG

In my post on CSS3 a few months back I mentioned some issues I had getting -moz-border-radius to clip content that it contained. After my writing the post the question came up a couple of times on stackoverflow, first from Brandon Wang and later a similar one from dougoftheabaci. Here is a simple example of the problem, the CSS is uncomplicated:

.target {
    border-radius: 20px;
    -moz-border-radius: 20px;
    -webkit-border-radius: 20px;
}

With that class applied direct to an img element it looks great in Safari and Chrome:

Example page in Chrome

But it doesn't work so well in Firefox:

Example page in Firefox

Today I came across the Applying SVG effects to HTML content article on the MDC wiki, one of the things it discusses is using SVG as a clipping mask for HTML elements. It occurred to me that it ought to be relatively straightforward to use a clipping mask to create the rounded corner effect directly on an img element in Firefox.

So I started off with the example code from the article, removed the circle, made the rectangle full size and used the rx and ry attributes to round the corners:

<svg:svg height="0">
    <svg:clipPath id="c1" clipPathUnits="objectBoundingBox">
        <svg:rect x="0" y="0" rx="0.05" ry="0.05" width="1" height="1"/>
    </svg:clipPath>
</svg:svg>

Then use a CSS class to apply it to my image:

.target { clip-path: url(#c1); }

It didn't work at first, but then I realised I'd created my document with a .html extension rather than .xhtml - to allow mixing of SVG into XHTML the document must have content type application/xhtml+xml. Once I fixed this the effect was exactly as I'd hoped:

Example SVG page in Firefox

Here is the full code. Of course, embedding it all this way isn't going to work for any browser other than Firefox 3.5, and serving application/xhtml+xml is going to break Internet Explorer, so it's not really a practical solution in it's current state. It's more useful to break the content into separate files, then the SVG can be served as image/svg+xml while your HTML is text/html. This final example works across browsers and will round the corners of the image in Chrome, Safari and Firefox.


Tweet this!

08/30/09

12:28:20 am, by delicious, 173 words, 1594 views   en-UK
Categories: Delicious

Links for August 30th


Tweet this!

08/23/09

12:04:20 am, by delicious, 79 words, 1588 views   en-UK
Categories: Delicious

Links for August 23rd


Tweet this!

08/16/09

12:35:05 am, by delicious, 164 words, 1021 views   en-UK
Categories: Delicious

Links for August 16th


Tweet this!

08/09/09

12:11:44 am, by delicious, 277 words, 3215 views   en-UK
Categories: Delicious

Links for August 9th


Tweet this!

08/03/09

03:10:22 pm, by robertc Email , 931 words, 14843 views   en-UK
Categories: Front End Web Development, Server Side Web Development, Standards, HTML and CSS

CSS with PHP

Last week I re-designed the home page of my personal website as the previous version was quite plain looking, mostly because I'd never gotten around to updating it. I had a visual theme for most of the sub-pages, a strong graphic as a background 'column' on the left and side, with the graphic differing by section. My idea was to reuse these graphics on the front page, except randomly select two of them each time the page loaded.

Since they were background images, I couldn't add a dynamic element in the page itself to contain them. I could perhaps have defined several new CSS classes to apply to the body element and then inserted a class name with PHP, but with six images, picking two, that means 30 class names which seemed inelegant, plus would be a bit of a pain if I later added an new section. So instead of making the page itself dynamic, I decided to make the CSS dynamic instead.

From a coding point of view the implementation is very straightforward. You rename your CSS file to be .php and make sure you return the correct content type in the header by adding this as your first line:

<?php header("Content-type: text/css"); ?>

I then just declared an array with all my images in and use a built in PHP function to give me two random images:

$bg_images = array('vertical_essays.jpg','vertical_default.jpg','vertical_books.jpg','vertical_football.jpg','vertical_writing.jpg','vertical_blog.jpg');
$bg_keys = array_rand($bg_images, 2);

Then in the CSS itself I just select the appropriate image:

html {
	background-image: url('/image/<?= $bg_images[$bg_keys[0]] ?>');
	background-repeat: no-repeat;
	background-attachment: fixed;
	background-position: bottom left;
}
body {
	background-image: url('/image/<?= $bg_images[$bg_keys[1]] ?>');
	background-repeat: no-repeat;
	background-attachment: fixed;
	background-position: bottom right;
}

After getting this working I then decided it would be fun to have my main navigation boxes have a background colour related to the images which are shown. The DeGraeve.com Color Palette Generator lets you generate a palette of colours from any image, so I put each of my background images into it and got a set of 'vibrant' and 'dull' colours for each image. I stuck this into another array, using the image names as keys and simply alternating vibrant and dull colours into an array value:

$colours = array(
    'vertical_essays.jpg' => array('#440','#553','#670','#332','#9b7','#eee'), 
    'vertical_default.jpg' => array('#560','#452','#02d','#36a','#8a7','#995'), 
    'vertical_books.jpg' => array('#720','#532','#d10','#a64','#d90','#a85'),
    'vertical_football.jpg' => array('#581','#564','#8a3','#785','#9c5','#eee'),
    'vertical_writing.jpg' => array('#644','#c73','#f20','#e82','#f30','#ded'),
    'vertical_blog.jpg' => array('#732','#644','#c30','#965','#c96','#cbb')
);

I could then set the background and border colours of the navigation boxes using the two random keys I'd already generated. To keep it simple I just had the left two boxes take colours from the left image, and the right box take colours from the right image:

#nav li.cv {
	background-color: <?= $colours[$bg_images[$bg_keys[0]]][0] ?>
	border-color: <?= $colours[$bg_images[$bg_keys[0]]][1] ?>
}
#nav li.writing {
	background-color: <?= $colours[$bg_images[$bg_keys[0]]][2] ?>
	border-color: <?= $colours[$bg_images[$bg_keys[0]]][3] ?>
}
#nav li.gameplan {
	background-color: <?= $colours[$bg_images[$bg_keys[1]]][4] ?>
	border-color: <?= $colours[$bg_images[$bg_keys[1]]][5] ?>
}

Here is the end result:

dotrob.com screenshot

As you can see, generating your CSS with PHP is just as easy as generating HTML with PHP. Even with my fairly simple minded implementation of the idea you can achieve some nice tricks. However, there are some drawbacks I ran into:

  • Because you're now editing a PHP file, you might have some trouble persuading your auto-completing CSS editor to recognise what's going on
  • You're now going to have to handle caching yourself, as your CSS is no longer a static file - not much of an issue for a small site like mine, but could be an unnecessary overhead on a large site
  • Once you've added background colours to the mix you have to consider your text and link foreground colours, I just settled for a light grey with light blue links which worked OK (but not great) on all the colours - could be a bit of a maintenance problem in the future (and a readability problem now)

Fortunately, there are possible ways round all these issues, especially if you were considering this technique for a serious site rather than a one page vanity domain &amp;#58;&amp;#41; You could always use your PHP to generate the appropriate set of colours for you from a given base colour - this saves you having to work out text, non-visited and visited link colours for each background colour. For bonus points, you could probably add the code which extract the base colour from the image in the first place to end up with a completely flexible solution. The first two issues both have the same solution - use an actual CSS file as a template, thus preserving the editor features, but use a server-side pre-processor to deliver the file to the web. This allows you, among other thing, to extend CSS with variables as well as taking care of all the cache issues for you.


Tweet this!

08/02/09

12:55:00 am, by delicious, 85 words, 1059 views   en-UK
Categories: Delicious

Links for August 2nd


Tweet this!

07/26/09

12:46:03 am, by delicious, 252 words, 2328 views   en-UK
Categories: Delicious

Links for July 26th


Tweet this!

07/19/09

01:14:41 am, by delicious, 254 words, 1424 views   en-UK
Categories: Delicious

Links for July 19th


Tweet this!

<< 1 ... 4 5 6 7 8 9 10 11 12 13 14 ... 32 >>