Thursday, November 3, 2005

CSS Style Sleuthing

WARNING: This blog entry was imported from my old blog on blogs.sun.com (which used different blogging software), so formatting and links may not be correct.


"How did that text end up with a blue color?"

"Why doesn't my style rule to add underlines on links work? Is some other rule overriding it?"

"What style class do I need to override to change the font size of my Table headers?"



These are some questions you may ask yourself when you're designing
your web applications using
CSS.
Whenever you're dealing with CSS, the Mozilla DOM Inspector
is your best friend. It lets you examine the CSS rules and computed styles
for each of the elements in your document.
While it is extremely helpful in answering these questions:

"What CSS style rules apply to this element?" and
"What computed styles apply to this element?"

it is not as helpful with the (in my opinion more important) earlier questions.
For example, to find out how a particular element ended up with a
blue color, you need to start at that element, then look at all the
style rules applying to the element, look through its style declarations,
see if any have anything to do with color, and if not, go up to its parent
element and repeat the search.



Fortunately, there's a trick you can use: Creator's hidden DOM inspector.
This is a tool which is not a supported part of the product;
in fact it's a facility I added to aid debugging the webform layout
engine itself. But it turns out many of the questions I have to ask
are the same ones a page designer will ask: "How did that box end up
that wide", "What HTML did that component render", and so on.
(I have blogged about this
before, but there are new facilities in there for
CSS debugging which now sets it apart from the Mozilla DOM inspector.)







Here's how it works. Control-alt click on a component. The nearest
CSS box computed around the mouse click is selected with a red highlight,
and the property sheet selects a lot of the Box properties corresponding
to the HTML element rendered for the component. (Most components render
multiple elements; the DOM inspector works at the HTML level so you get
to see how rules apply to individual HTML elements.)



A couple of months ago I also added a little window display showing the
box hierarchy, so you can easily walk up and down in the box tree, like
Mozilla's DOM inspector lets you walk through the HTML Element tree.
One important feature here is that ask you click in the displayed page,
it expands nodes and selects the corresponding box. That's a feature I've
always missed in Mozilla's DOM inspector. Anyway, this part may have been
added right after EA2 went out so may not be available in your
version yet. But you can walk the hiearchy by pressing Escape to select
the parent box. Without the box tree window there's no way to descend;
you'll have to click on a box to select the closest leaf and then work
your way back up.



Here are the windows:













In the Layout Info window (on the left), the HTML tag is shown in angle brackets <>, and then the JSF component (if any) id is shown in italic.



The property display displays a number of interesting properties. I
may get back to some other ones later. But for CSS debugging, there
are two that really matter.



First, Computed Style:.
If you open the customizer, you'll see something like this:






This tells you a number of things. First, an asterisk (*) on the
left tells you that the value shown is different from the default
value of the property (e.g. has been overridden by somebody).
You then see the property, and the actual computed value.
The CSS2 properties are listed alphabetically.



Then, and this is the important part, it will try to tell you
where that particular value is coming from! This is shown
as the stylesheet name with a line number. This helps you answer
the initial questions. You can find the rule which is overriding
your intended rule.



(Note: Sometimes the line numbers are wrong - off by a couple.
Sometimes the line numbers are completely wrong. This happens
because I deliberately implemented the code which tracks style
usage to be extremely low overhead (since it's for debugging only),
and in particular, the CSS code tries to share Value objects
when possible. In cases where a single value object is used in
multiple places I cannot attribute different usage references,
so only the last one is recorded. Luckily, this doesn't happen
with attributes you are most likely to be interested in: font size,
color, width, height, etc.)



A second related facility is the "Rules" property. This
property lets you view which CSS rules apply to a particular
element. It is similar to the facility in the Mozilla DOM inspector.






(I added this property when checking my
performance optimization for CSS rule checking,
so it may not yet be in the version you're running.)






Here's a slightly different example. Take a look at the google
page for example. If I click on the word "New" (which is in red) because
I wonder where the Red is coming from, I see this in the Computed Style property editor:









As you can see, the color property is getting its value from an HTML
attribute.
Indeed, the JSP contains this:


<font color="red">New!</font>

The color is coming from the color attribute. It's not always a
direct mapping; for example, a bgcolor attribute maps to the CSS
background-color property, etc.



Note that since this is a debugging tool, I have packed in a lot of
information, and this information is not cached in any way, so the display
is pretty slow. Also, the window is not tried to be kept up to date
etc. so sometimes you need to close the Layout Info window, and
reselect boxes on the designer surface to see their updated properties
etc.



By the way, on the Mac, you need to use Alt-Click instead of
Control-Alt click, because Ctrl-Alt click is "reserved" on the mac.



Happy sleuthing!


16 comments:

  1. Hi Tor,
    first thank you for this nice tutorial and for your great blog!
    I've some questions:
    1. How can i create my own theme in a productive way? (i think most web developers need a theme creation editor or something ..., there is a great need to customize the look and feel)
    are there any plans?
    2. The dataprovider's are simple to use and ok in many cases. Are there any plans to support JDO in Creator (visual modeling of entities an so on - this is an important feature to push the productivity, Sun make standards but no cash, no automatic mapping tool from sun, only horror tools out there ... - it's a great marked ...)
    are there any plans?
    3. Sun Studio Ent. 8 is free.
    Why there is no MacOSX Version?? (I think i ask the right one ... ;-)) )
    Matthias

    ReplyDelete
  2. Hi Tor,
    I am using background images for my forms and I
    want to preload them rather than having components
    and data arriving on a white screen.
    Each image represents a business category which is
    assoiciated with a style class.
    Can you think of anyway to preload images that are
    determined at runtime or can i ensure that the form's image is fully rendered before the other components.
    Cheers,
    paul (JSC user)

    ReplyDelete
  3. Sorry Paul... Having the page lazily update itself (and re-render) as external resources such as images become available is a feature of most web browsers - and I don't have any ideas for how it can be defeated (although it might be possible with some fancy javascript).
    One simple idea you can try is to have a "launch" page. This would be a white page with a simple centered label, something like "Now launching application, please wait". This page would also have an -invisible- image on it (drop a graphic image, then go change its Style property to include "visibility: hidden" (use ; as a separator).
    After a few seconds the launch page (or perhaps an explicit button) will take you to your main application.
    The whole point here is that on the "launch" page (Which doesn't have your page background) you are causing the browser to load the image (but not show it). This should ensure that the image is in the browser cache, such that when you hit the real page, the image is already there and there is no delay. This of course assumes that the delay is long enough that the image always gets fully loaded, even for users with slow connections. You also have to ensure that the browser gets the same full URL to the image such that the image caching works.
    Good luck and if you come up with something more clever, do share!

    ReplyDelete
  4. Thanks for your reply Tor,
    I will let you know how I get on.
    Found the folowing script used by many sites.
    I think it might be generated by a Macromedia
    tool. Will give it a try
    <script language="JavaScript" type="text/javascript">
    <!--
    function MM_preloadImages() { //v3.0
    var d=document;
    if(d.images)
    {
    if(!d.MM_p)
    d.MM_p=new Array();
    var i,
    j=d.MM_p.length,a=MM_preloadImages.arguments;
    for(i=0; i<a.length; i++)
    if (a[i].indexOf("#")!=0)
    {
    d.MM_p[j]=new Image;
    d.MM_p[j++].src=a[i];}}
    }
    //-->
    cheers,
    paul
    </script>

    ReplyDelete
  5. function MM_preloadImages() { //v3.0
    var d=document; if(d.images){ if(!d.MM_p) d.MM_p=new Array();
    var i,j=d.MM_p.length,a=MM_preloadImages.arguments; for(i=0; i<a.length; i++)
    if (a[i].indexOf("#")!=0){ d.MM_p[j]=new Image; d.MM_p[j++].src=a[i];}}
    }

    ReplyDelete
  6. a.length; i++)
    if (a[i].indexOf("#")!=0){ d.MM_p[j]=new Image; d.MM_p[j++].src=a[i];}}
    }

    ReplyDelete
  7. Alexander KlimenkoMay 31, 2006 at 5:52 AM

    Hello Tor,
    thanks a lot for you comprehensive log.
    The question I have concerns using custom CSS layouts with JSC2. My friends and I like the job you did to put JSC one level up on top in comparison with other JSF-related IDEs. The main advantage from our point of view is the visual designer with its nice JSC2 components like DataTable. The only thing I can't understand how to work with custom CSS layout. I found out 3 level of CSS overriding facility (master_css(Theme), stylesheet(styleClass), inline (style). The problem is that CSS inheritance related to enclosing/enclosed tag is not working. For instance, I've created some font properties for body tag in stylesheet.css but they are not propagated to nestedLayout panel. Does it mean that, for example, font properties must be defined for each nested LayoutPanel separately?
    Kind regards,
    Alex

    ReplyDelete
  8. No - what's happening here is that the themes are using style classes. This means that the rules generally get higher precedence than simply inherited font attributes. This means that it's a bit tricky for you to override colors defined by a theme. One way is to simply look for which styleclass definitions the theme is picking up, and overriding those yourself.

    ReplyDelete
  9. Alexander KlimenkoJune 2, 2006 at 7:35 AM

    Tor,
    thank you for your response.
    The thing I've found out is that I have to replace short-hand CSS from DreamWeaver with long-hand one in order to see it in JSC2 DOM Inspector. That's why I could't see CSS applied. Now it is getting better.
    Kind regards,
    Alex

    ReplyDelete
  10. Do you have an example of a shorthand rule from Dreamweaver that works (in browsers) but not in Creator - along with the expanded rule?

    ReplyDelete
  11. Alexander KlimenkoJune 2, 2006 at 6:09 PM

    Where I can send the file with screenshots? I have created screenshots before applying longhand CSS and after.

    ReplyDelete
  12. I don't need the screenshots (I don't think), what I need is the CSS rules so we can check them against the CSS parser and layout routines.

    ReplyDelete
  13. Alexander KlimenkoJune 3, 2006 at 7:06 AM

    Regarding properties inheritance:


    emx_nav_left.css PART:

    ----------------------------


    #pagecell1{

    position:absolute;

    top: 112px;

    left: 2%;

    right: 2%;

    width:95.6%;

    background-color: #ffffff;

    }

    #pageNav{

    float: left;

    width: 178px;

    padding: 0px;

    background-color: #F5f7f7;

    border-right: 1px solid #cccccc;

    border-bottom: 1px solid #cccccc;

    font: small Verdana,sans-serif;

    }

    .relatedLinks{

    border-bottom: 1px solid #cccccc;

    margin: 0px;

    padding: 0px 0px 10px 10px

    }


    JSF code

    ----------------------------

    <div id="pagecell1">

    <div id="pageNav">

    <div class="relatedLinks">



    Related Link



    </div>

    </div>

    </div>


    RULES (Ctrl+Alt +click on relatedLinks div)

    ----------------------------
    jar:file:/C:/Sun/Creator2_1/rave2.0/modules/ext/defaulttheme.jar!/com/sun/rave/web/ui/defaulttheme/css/css_master.css:

    BODY, TH, TD, P, DIV, SPAN, INPUT, BUTTON, SELECT, TEXTAREA, FORM, B, STRONG, I, U,
    H1, H2, H3, H4, H5, H6, DL, DD, DT, UL, LI, OL, OPTION, OPTGROUP, A {

    font-family: sans-serif;

    font-size: 12px;

    }


    /resources/emx_nav_left.css:

    *.relatedLinks {

    border-bottom-width: 1px;

    border-bottom-style: solid;

    border-bottom-color: rgb(204, 204, 204);

    margin-left: 0px;

    margin-right: 0px;

    margin-top: 0px;

    margin-bottom: 0px;

    padding-top: 0px;

    padding-right: 0px;

    padding-bottom: 10px;

    padding-left: 10px;

    }


    Conclusions

    ----------------------------

    1. There are no rules found in the default theme (css_master.css) that take precedence over the rules defined in the emx_nav_left.css (no rules with the same names are defined in css_master).

    2. Neither #pagecell1 nor #pageNav is going before .relatedLinks rule in RULES inspector. It is not DOM Inspector bug because in designer I can see no “small Verdana,sans-serif;” fonts in div with class="relatedLinks” also.


    Kind Regards,

    Alex

    ReplyDelete
  14. Alexander KlimenkoJune 3, 2006 at 7:28 AM

    Regarding shorthand:


    RULES from DOM Inspector

    -----------------------------------

    *.story h3 {

    font-weight: bold;

    font-size: 125%;

    font-family: sans-serif;

    color: rgb(0, 0, 0);

    }


    Rule from emx_nav_left.css:

    ---------------------------

    .story h3{

    font: bold 125% Arial,sans-serif;

    color: #000000;

    }

    ReplyDelete
  15. Alexander KlimenkoJune 4, 2006 at 3:30 AM

    Sorry about 1st one. It is my fault.


    I've missed the following:

    .feature{

    padding: 0px 0px 10px 10px;

    font-size: 80%;

    min-height: 200px;

    height: 200px;

    }


    So, having css_master.css - 12px, h3 - font-size: 100%, .feature - font-size: 80%, *.feature h3 - font-size: 175% I got 16.666px


    Defenitely, I have to go to bad earlier (we have good time difference, so it was 12:00AM really :)

    ReplyDelete