Archive for the ‘CSS’ Category
jQuery Watermark Plugin (Version 1.0.1)
I have just uploaded version 1.0.1 of my watermark plugin.
This release fixes positioning problems users have encountered when:
- Browser windows is resized.
- Elements are added or removed.
- Visibility of input element is toggled.
In this updated version, instead of absolutely positioning the watermark <label> element based on the (initial) position of the <input> element, I inject an extra <span> before the <input> element, and use the <span> as the positioning container for the watermark <label>.
As the <span> is “statically” positioned, it “follows” the <input> element, and consequently, the watermark <label> also “follows” the <input> element.
Enjoy!
Are you having trouble aligning form fields?
If you specify the same width (and/or height) to your form fields, i.e. inputs, textareas and selects, and wondered why they don’t line up, then you need to know the difference between their box models.
The following elements follow the W3C Box Model: (i.e. width excludes paddings and borders)
- <input type=”file” />
- <input type=”text” />
- <textarea />
And the following elements follow the Traditional (IE) Box Model: (i.e. width includes paddings and borders)
- <input type=”button” />
- <input type=”checkbox” />
- <input type=”radio” />
- <input type=”reset” />
- <input type=”submit” />
- <select />
So, you need to ensure that the width (and/or height) of the second set of elements should equal width + paddings + borders of the first set of elements.
jQuery (ASP.NET) Validator Callout Plugin
This plugin enhances the presentation of ASP.NET validator controls, by displaying the validation error message inside a (popup) callout box, like this:

This plugin is similar to the ValidatorCallout extender in the ASP.NET AJAX Control Toolkit.
Download
Download the latest release from http://plugins.jquery.com/project/updnValidatorCallout
Usage
Simply call jQuery.updnValidatorCallout.attachAll() to attach the plugin to all validators on your page.
For example:
jQuery(document).ready(function($) {
$.updnValidatorCallout.attachAll();
});
You can style the callout box and pointer by specifying the ”calloutCssClass” and “pointerCssClass” options:
jQuery(document).ready(function($) {
$.updnWatermark.attachAll({
calloutCssClass: "myValidatorCallout",
pointerCssClass: "myValidatorCalloutPointer",
);
});
You can also style the input element and all associated labels that are in error state by specifying the “errorInputCssClass” and “errorLabelCssClass” options:
jQuery(document).ready(function($) {
$.updnWatermark.attachAll({
calloutCssClass: "myValidatorCallout",
pointerCssClass: "myValidatorCalloutPointer",
errorInputCssClass: "myValidationErrorInput",
errorLabelCssClass: "myValidationErrorLabel" }
);
});
Alternatively, you can simply style the default CSS classes provided by the plugin:
.updnValidatorCallout
{
background-color: #fcc;
color: #900;
padding: 5px;
margin: -5px 0 0 10px;
position: relative;
}
.updnValidatorCalloutPointer
{
position: absolute;
left: 0;
top: 7px;
margin: 0 0 0 -10px;
width: 0;
height: 0;
border-top: 7px solid transparent;
border-bottom: 7px solid transparent;
border-right: 10px solid #fcc;
border-left: 0;
}
.updnValidationErrorInput
{
background-color: #fcc;
}
.updnValidationErrorLabel
{
color: #900;
}
N.B. For the triangular pointer, I used a pure CSS solution as detailed in this article.
jQuery Watermark Plugin
!!! Latest release 1.0.1 now available !!!
This plugin turns the tooltip text specified in the title attribute of your input element into a watermark, like this:

This watermark plugin can safely be used on text, password and textarea elements, as it does not alter the value of the fields, and therefore does not affect form submits or AJAX calls.
The plugin works by creating a label element using the text specified in the title attribute of each selected input element, and inserting the label element before the input element, absolutely positioned (relative to the input element’s positioning context) to appear ”behind” or “inside” the field.
Download
Download the latest release from http://plugins.jquery.com/project/updnWatermark
Usage
Specify the watermark text in the title attribute of each input element:
<input id="username" name="username" type="text" title="Please enter username" /> <input id="password" name="password" type="password" title="Please enter password" /> <textarea id="description" name="description" title="Please enter description"></textarea>
Then simply call jQuery.updnWatermark.attachAll() to attach the plugin to all text, password and textarea elements in the document.
For example:
jQuery(document).ready(function($) {
$.updnWatermark.attachAll();
});
You can style the watermark by supplying a class via the “cssClass” option:
jQuery(document).ready(function($) {
$.updnWatermark.attachAll({ cssClass: "myWatermark" });
});
Alternatively, just style the default “updnWatermark” class:
.updnWatermark {
color: #999;
font-family: Sans-Serif;
font-size: small;
font-style: italic;
padding: 2px;
}
Getting the page and viewport dimensions using jQuery
To get the width and height of the whole page (document), use:
var pageWidth = $(document).width(); var pageHeight = $(document).height();
To get the width and height of the viewport (window), use:
var viewportWidth = $(window).width(); var viewportHeight = $(window).height();
With Opera 9.5, $(window).height() returns the document height, as documented here.
To fix it, use:
var viewportHeight = window.innerHeight ? window.innerHeight : $(window).height();
Table cell box model quirk in Firefox
I encountered a quirk (or possibly a bug?) in Firefox, where the calculation of the total box height for a table cell seems to ignore the height specified in CSS.
To demonstrate the quirk, I created this simple page:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
<title>Table Cell Box Model Sample</title>
<style type="text/css">
table tbody tr td
{
padding: 10px;
height: 50px;
width: 50px;
background-color: #ffc;
border: solid 1px #f00;
}
</style>
</head>
<body>
<table>
<tbody>
<tr>
<td>Cell</td>
</tr>
</tbody>
</table>
</body>
</html>
View the page in Internet Explorer or Google Chrome and you get:

View the page in Firefox and you get:

To fix the problem, simply add “line-height” to the CSS ruleset for the table cell:
table tbody tr td
{
padding: 10px;
height: 50px;
line-height: 50px; /* Fix for Firefox */
width: 50px;
background-color: #ffc;
border: solid 1px #f00;
}
Alternatively, wrap your content in a block element (e.g. div) and specify the height:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
<title>Table Cell Box Model Sample</title>
<style type="text/css">
div.content
{
height: 50px;
width: 50px;
padding: 10px;
}
table tbody tr td
{
padding: 0;
background-color: #ffc;
border: solid 1px #f00;
}
</style>
</head>
<body>
<table>
<tbody>
<tr>
<td>
<div class="content">Cell</div>
</td>
</tr>
</tbody>
</table>
</body>
</html>
By the way, the width is not affected and renders correctly, so IMHO the CSS height quirk must be a bug!
Related links:
Improved text box watermarking
There are many implementations of text box watermarking, but they all involve changing the actual value of the text box, which means you have to ensure the watermark text is removed before submitting the form, this can get tricky if you also use a client-side form validation framework.
I have come up with an implementation that does not modify the value of the text box, but instead, displays the watermark “behind” the text box.
![]()
Here is the HTML structure:
<span class="updn-wm"> <label for="txtLocation">e.g. London or W1</label> <input id="txtLocation" id="txtLocation" type="text" /> </span>
The outer <span> element acts as a positioning parent for the <label> element (i.e. watermark) and the <input> element (i.e. text box).
The <input> element is statically positioned and the <label> element is absolutely positioned to appear behind the <input> element.
Here is the CSS:
.updn-wm
{
/* make this the positioning parent */
position: relative;
}
.updn-wm label
{
/* place watermark behind text box */
position: absolute;
left: 2px;
top: 2px;
/* watermark styling */
color: #999;
font-family: verdana, sans-serif;
font-size: small;
font-style: normal;
}
.updn-wm input
{
/* make text box transparent */
background: none;
/* text box styling */
border: solid 1px #999;
font-family: verdana, sans-serif;
font-size: small;
font-style: normal;
}
For the behavior script, I used jQuery because it’s quick and easy to work with:
$(document).ready(function() {
$(".updn-wm").each(
function() {
$("input[type='text']", this).each(
function() {
// initial state of watermark
if (this.value.length > 0) {
$("label", this.parentNode).hide();
}
// show/hide watermark text
$(this).focus(
function() {
if (this.value.length == 0) {
$("label", this.parentNode).hide();
}
}
).keydown(
function() {
if (this.value.length == 0) {
$("label", this.parentNode).hide();
}
}
).blur(
function() {
if (this.value.length == 0) {
$("label", this.parentNode).show();
}
}
).change(
function() {
if (this.value.length == 0) {
$("label", this.parentNode).show();
}
}
);
}
);
}
);
});
Note: Whitespaces between tags causes IE to render incorrectly, a quick fix is to join the tags together like so:
<span class="updn-wm"><label for="txtLocation">e.g. London or W1</label><input id="txtLocation" id="txtLocation" type="text" /></span>
Icons and images library in Visual Studio 2008
This is a super tip from Sara Ford’s WebLog! There is a library of icons and images hidden in the depth of Visual Studio, in my installation, the zip file is located at C:\Program Files\Microsoft Visual Studio 9.0\Common7\VS2008ImageLibrary\1033.
Here are some examples:
![]() |
Image Corners Extender Control
The prevalent use of styled borders (e.g. rounded corners) by our designers have caused much debate amongst the developers as to which technique should be employed to achieve the desired result. The Backgrounds and Borders Module in CSS Level 3 would be ideal, but we have to wait until that becomes ubiquitous.
In this post, I present to you an extender control I created to add image corners to <asp:Panel> controls. The extender works by injecting additional <div> elements into the DOM and style each with a background image.
Below is the source code for the server-side extender control:
using System.Collections.Generic;
using System.Web.UI;
using System.Web.UI.WebControls;
[assembly: WebResource("UPDN.ImageCornersBehavior.js", "text/javascript")]
namespace UPDN
{
///
///
[TargetControlType(typeof(Panel))]
public class ImageCornersExtender : ExtenderControl
{
public string TopBorderImageUrl { get; set; }
public string RightBorderImageUrl { get; set; }
public string BottomBorderImageUrl { get; set; }
public string LeftBorderImageUrl { get; set; }
public string TopLeftCornerImageUrl { get; set; }
public string TopRightCornerImageUrl { get; set; }
public string BottomLeftCornerImageUrl { get; set; }
public string BottomRightCornerImageUrl { get; set; }
public string MiddleImageUrl { get; set; }
protected override IEnumerable
{
var descriptor = new ScriptControlDescriptor(“UPDN.ImageCornersBehavior”, targetControl.ClientID);
var imageUrls = new Dictionary
if (!string.IsNullOrEmpty(TopBorderImageUrl))
imageUrls.Add(“t”, TopBorderImageUrl);
if (!string.IsNullOrEmpty(RightBorderImageUrl))
imageUrls.Add(“r”, RightBorderImageUrl);
if (!string.IsNullOrEmpty(BottomBorderImageUrl))
imageUrls.Add(“b”, BottomBorderImageUrl);
if (!string.IsNullOrEmpty(LeftBorderImageUrl))
imageUrls.Add(“l”, LeftBorderImageUrl);
if (!string.IsNullOrEmpty(TopLeftCornerImageUrl))
imageUrls.Add(“tl”, TopLeftCornerImageUrl);
if (!string.IsNullOrEmpty(TopRightCornerImageUrl))
imageUrls.Add(“tr”, TopRightCornerImageUrl);
if (!string.IsNullOrEmpty(BottomLeftCornerImageUrl))
imageUrls.Add(“bl”, BottomLeftCornerImageUrl);
if (!string.IsNullOrEmpty(BottomRightCornerImageUrl))
imageUrls.Add(“br”, BottomRightCornerImageUrl);
if (!string.IsNullOrEmpty(MiddleImageUrl))
imageUrls.Add(“m”, MiddleImageUrl);
descriptor.AddProperty(“imageUrls”, imageUrls);
yield return descriptor;
}
protected override IEnumerable
{
yield return new ScriptReference(“UPDN.ImageCornersBehavior.js”, this.GetType().Assembly.FullName);
}
}
}
And the source code for the client-side behavior:
Type.registerNamespace("UPDN");
UPDN.ImageCornersBehavior = function(element) {
UPDN.ImageCornersBehavior.initializeBase(this, [element]);
// keys: t, l, b, r, tl, tr, bl, br
this._imageUrls = null;
}
UPDN.ImageCornersBehavior.prototype = {
initialize: function() {
UPDN.ImageCornersBehavior.callBaseMethod(this, "initialize");
var el = this.get_element();
var imagesUrls = this.get_imageUrls();
var containers = [];
// create border elements
if (imagesUrls["t"]) {
var t = document.createElement("div");
t.style.background = "url(" + imagesUrls["t"] + ") repeat-x top left";
containers.push(t);
}
if (imagesUrls["r"]) {
var r = document.createElement("div");
r.style.background = "url(" + imagesUrls["r"] + ") repeat-y top right";
containers.push(r);
}
if (imagesUrls["b"]) {
var b = document.createElement("div");
b.style.background = "url(" + imagesUrls["b"] + ") repeat-x bottom left";
containers.push(b);
}
if (imagesUrls["l"]) {
var l = document.createElement("div");
l.style.background = "url(" + imagesUrls["l"] + ") repeat-y top left";
containers.push(l);
}
if (imagesUrls["tl"]) {
var tl = document.createElement("div");
tl.style.background = "url(" + imagesUrls["tl"] + ") no-repeat top left";
containers.push(tl);
}
if (imagesUrls["tr"]) {
var tr = document.createElement("div");
tr.style.background = "url(" + imagesUrls["tr"] + ") no-repeat top right";
containers.push(tr);
}
if (imagesUrls["bl"]) {
var bl = document.createElement("div");
bl.style.background = "url(" + imagesUrls["bl"] + ") no-repeat bottom left";
containers.push(bl);
}
if (imagesUrls["br"]) {
var br = document.createElement("div");
br.style.background = "url(" + imagesUrls["br"] + ") no-repeat bottom right";
containers.push(br);
}
if (containers.length > 0) {
// create content container
var m = document.createElement("div");
m.className = "content";
// move child elements of target element into content container
this._moveChildren(el, m);
// set middle image as background of target element
if (imagesUrls["m"]) {
el.style.background = "url(" + imagesUrls["m"] + ") repeat top left";
}
containers.push(m);
// inject containers into DOM
el.appendChild(containers[0]);
for (var i = 1; i < containers.length; i++) {
containers[i - 1].appendChild(containers[i]);
}
}
},
dispose: function() {
//Add custom dispose actions here
UPDN.ImageCornersBehavior.callBaseMethod(this, "dispose");
},
_moveChildren: function(srcEl, destEl) {
while (srcEl.hasChildNodes()) {
var child = srcEl.childNodes[0];
destEl.appendChild(child);
}
},
get_imageUrls: function() {
return this._imageUrls;
},
set_imageUrls: function(value) {
this._imageUrls = value;
}
}
UPDN.ImageCornersBehavior.registerClass("UPDN.ImageCornersBehavior", Sys.UI.Behavior);
To use the extender, place an <asp:Panel> control on the page:
<asp:Panel ID="Panel1" runat="server" CssClass="box1">
This box is styled using 8 images. Lorem ipsum no etiam perfecto his, per adhuc maiorum epicurei eu. Laoreet signiferumque in mel, ne vel dicat percipit instructior. An eum veniam decore perpetua, nam laudem praesent at. Exerci accumsan contentiones est ei, appetere gloriatur et qui, ea suscipit senserit consectetuer mei.
</asp:Panel>
Then add the extender, set the TargetControlID to the ID of the <asp:Panel> control, and specify the images required to achieve your design. For this panel, I require eight images, four for the borders and four for the corners:
<updn:ImageCornersExtender ID="ImageCornersExtender1" runat="server"
TargetControlID="Panel1"
TopBorderImageUrl="img/box1/t.gif"
RightBorderImageUrl="img/box1/r.gif"
BottomBorderImageUrl="img/box1/b.gif"
LeftBorderImageUrl="img/box1/l.gif"
TopLeftCornerImageUrl="img/box1/tl.gif"
TopRightCornerImageUrl="img/box1/tr.gif"
BottomLeftCornerImageUrl="img/box1/bl.gif"
BottomRightCornerImageUrl="img/box1/br.gif"
/>
Here is how the complete example looks like:

Download the source code and example from my SkyDrive.
Coming soon! My CSS Tutorial
I did a CSS tutorial session at work, and I promised to make all the material online, so over the next few weeks, I will upload them to my CSS Tutorial page.
