Showing posts with label html. Show all posts
Showing posts with label html. Show all posts

Friday, August 20, 2010

Restoring Browser Functions to Clickable DIVs Without Javascript

Occasionally the situation comes up in web development where you have a highly styled tag such as
<div> or <li> that you want to make clickable.  This often happens when you have a list of items in which you want to make the entire item clickble instead of just the title for example.  The standard fare for doing so is to set { cursor: pointer; } with CSS then to bind the .click event to the tag (in jQuery as so)....

$('#myDivTag').click(function() {
    // your code here
});

Don't get me wrong -- this does work.  However, in doing this what you loose is the standard functionality that most viewers are used to; things like middle clicking to open in a new tab, right-click to copy URL address, and so on.  There is also the lag between when the page renders visibly to the user but the javascript hasn't downloaded and $(document).ready hasn't yet fired.  In this case the tag will not be clickable but the mouse cursor will indicate that it should be.

I've been dealing with this more so lately and there are a couple of ways to solve this problem.

The first is to wrap the <div> (or li or whatever else) tag in an anchor tag <a> and set that anchor tag to { display: block; }.

<style type="text/css">
   #myDivWrapper { display: block; }
   #myDiv {  }
</style>

<a id="myDivWrapper">
    <div id="myDiv">
       ... content ...
    </div>
</a>

By wrapping the div tag in an anchor you've restored the default functionality viewers are used to with a clickable item.  This works in most browsers but for the most part things like <div> and <li> are not allowed inside of an anchor tag per HTML language specifications.  In a sense in doing something like this you are rolling the dice that the next version of IE9 strict mode won't render when it hits this.

It also feels kind of  weird, because all of the styling that was on #myDiv, things like height, width, float, etc., now need to be applied to the anchor tag instead.  And no one likes wrappers. They just clutter things up.

The 2nd way to solve this problem which I've started using lately is to have an absolutely positioned anchor overlay the area of the div.  Consider the following...

<style type="text/css">
    #myDiv { position: relative; }
    a.clickable-overlay {
        position: absolute;
        top: 0;
        left: 0;
        height: 100%;
        width: 100%;
        z-index: 1;
        display: block;
        background-color: transparent;
    }
</style>

<div id="myDiv">
    ... content ...
    <a class="clickable-overlay" href="#wherever"></a>
</div>

Here's what's happening:  At the end of the <div> (or li or whatever) we're adding an anchor tag.  The parent div is set to { position: relative }, and the anchor tag to { position: absolute; }.  If you're not familiar with position absolute you're missing out.  The way it is designed to work is that any element positioned absolutely is done so in relation to it's parent (or any parent's parent) that is positioned either relatively or absolutely.  What this means is that in setting our <div> tag to position: relative the anchor tag with position absolute will be positioned relative to the div.  Top 0 and left 0 will be the top left of the div,  and height 100%, width 100% will cause the anchor to fill out the area of the div.

The result is that we are left with a transparent anchor tag that completely overlays the area of the div, providing the default clickable behavior users expect.  The last CSS trick to making this work is to set z-index to 1, forcing the browser to always render the anchor tag over whatever content is in the div.

The positives to this method are that 1. we restore the expected clickable behavior without javascript (meaning it also works as soon as that markup is rendered and not when $(document).ready is fired) and 2. we're using correct HTML syntax.

I should point out there is a downside to this method, in that because the anchor overlays the div, the contents of the div are no longer selectable or clickable.  Depending on your application this may be negligible.

Tuesday, November 17, 2009

A Truly Modular Web Framework

Web development is weird. It's weird because the rendering of the UI (in HTML) feels so incredibly disconnected from the logic and objects that are represented by the UI. It's weird because the UI is usually rendered by a server-side template facility, but is occasionally rendered by cilent-side javascript.


Here's an example. I find the decorator pattern really cool. Let's say I'm writing a blog. Actually, everyone writes blogs. Let's say I'm writing a Stack Overflow clone. In Stack Overflow users can ask questions. Other users can answer them. Users can also comment on a question (different from an answer), or comment on an answer made by another user. The shared functionality is placing comments on an object.

The mechanics of a comment aren't particularly unique that they need to be bound to a specific object. A UI is presented for a user to type in a message. The server should store the messages and associate them with a specific object.

So let's say in this example the comment functionality is implemented as a decorator generically which can be applied to any object. So we have the question functionality, implemented perhaps as a class, and we can decorate it with the comment functionality. If later we decided to implement a "News" section, and need each news post to also have comments, we could also decorate the news posts using the same decorator as well. The comment functionality at this point is a self-contained decorator.

Programatically this doesn't seem like a difficult suggestion (maybe), but what happens when we need to render this out to HTML? Even worse, let's say the comment functionality requires javascript to fetch comments via AJAX -- then what?

I think the problem here is that whatever is doing the rendering doesn't know what the object Question or Answer looks like. It also doesn't know what the decorator Comments looks like either. If it did, it could render them intelligently. I'm thinking of decorated rendering here.

Functionality similar to what I'm describing can be achieved in current web frameworks, but usually through things like template tags, framework widgets, or partially rendered views. But that's not quite what I'm talking about. It still requires a lot of repetition and isn't really modular. Template tags still need to be coded very specifically.

Part of the issue is that in web development frameworks we are using HTML to describe too many things. Take Django's template system, which despite many people's complaints, is quite functional and I actually kind of like. Django templates provide the facilities of context (passing variable data to the template), template tags (custom bits of code that can be arbitrarily executed) and filters (helpers to modify data to conform to a particular output).

But for each page template that is created, the following things are being handled in that one template:
  1. How a given object should be rendered
  2. How the page is layed out
  3. What media files need to be linked/included in order for this page to rendered properly (js/css/etc.)'
I'm thinking out loud here, but what would a rendering system (and supporting framework) look like which separated what the template system did into separate pieces?
  • Each object has it's own multiple HTML "interpretations", outfits if you will for the class. Decorators can call the decorated class's outfits if needed.
  • Page templates become more semantic and less about display -- they're interested in where pieces go on the page, not necessarily the markup to render it to appear a certain way. More of an outline than a sea of div tags. It seems very often the task of laying out what goes on a page, and implementing the UI are two completely separate tasks, and yet most template systems I've used force you to do them together.
  • Media files are handled programatically in code, somewhere, somehow. An object outfit can for example say "I need this javascript file" and the template engine will react accordingly. This prevents <script> tags and @import statements being strewn all over, and allows the framework to pass those media files off to a handler that decide if something should be done with them (ie automatically put <script> at bottom and <link> at the top, compress the JS, etc.). Disclaimer: This is probably a harder problem than I'm thinking it is, especially when AJAX gets involved.
More to come on this. I might have to do some experimental code. Should template engines help you by handling some pieces of the Javascript on the client? Hmm...

  © Blogger template 'Minimalist G' by Ourblogtemplates.com 2008

Back to TOP