Thursday, February 12, 2009

JSR-168/JSR-286 Portlet Developer Styling Recommendations

The following is a preposed "how-to" for styling JSR-168/JSR-286 portlets. If you've looked at JSR-168/JSR-286's PLT.C section, and looked at open-source portlets that are out there (as of early 2009), you've probably noticed that very few have implemented all of PLT.C. With the following recommendations, you can develop portlets that can be easily styled/skinned by a portlet administrator, even if you choose to ignore PLT.C.

JSR-168/JSR-286 Portlet Developer Styling Recommendations

At a minimum for portlet developers to develop a portlet that portal administrators can easily skin:
Rendered HTML (JSP/etc.) requirements:
1. All top level elements in the portlet should have a unique (CSS) class (attribute). If an id is defined (which really shouldn't be used in styling because it changes depending on portlet instance, but could be defined for javascript to be used on the same page) should be "<portlet:namespace/>someuniqueid".
2. All elements that may need classes in the portlet (for selected row/line item, alternate row coloring in table rows/line items, ...) should have classes defined.
3. Portlet should include its own default CSS for example in WEB-INF/css/(nameofportlet).css (for maven 2 build normal dir structure would be src/main/webapp/css/(nameofportlet).css) and then be referenced in JSP/JSP include (if using JSP) as <style type=\"text/css\">@import url(\"<%=request.getContextPath()%>/css/(nameofportlet).css\");</style> (can use multiple CSS files per portlet if desired)
4. The CSS included with the portlet should define all styles like toplevelelementname.toplevelelementclassname ...
For example, in the MailPortlet, a level 3 header within the top level div with class named "mailportletcontainer" and id "mailportletcontainerid" that would be styled in the portlet's own CSS file as:
.mailportletcontainer h3 { ... }
Then the portal adminstrator could define the following in the skin to override it like:
div.mailportletcontainer h3 { ... }
Because the additional element selector will make it win over the other one.
This override by only the top level elements/containers also works for more complex combinations of selectors. For example, in the portlet's own CSS file the portlet developer may have specified:
.mailportletcontainer form.mailPortletMailAccountForm 
a#mailPortletResetMailAccountsLink { ... }
Then the portal adminstrator could define the following in the skin to override it like:
div.mailportletcontainer form.mailPortletMailAccountForm 
a#mailPortletResetMailAccountsLink { ... }
Because 2 id selector + 1 class selector beats 1 id selector + 2 class selectors.
Even without having to keep track of the complexity of specificity, a portal admin could just copy the portlet's CSS into their skin file, and just add the top level container's element name to the beginning of each class where it is defined. Ss long as the portlet developers use that convention, the portal admin then has full control over the portlet's default CSS!
4. CSS namespaces are an *additional* way to try to help with making sure that class and id names are unique to the portlet, to help the portlet CSS from affecting other portlets if there is a naming conflict, but that doesn't mean that the portlet developer should get lax and not use id and class names that would still have a good chance at being unique on a page containing other portlets.
5. JSR-168/JSR-286 PLT.C defined classes (named "portlet-*") are not recommended to be used even though they may be defined by the portal in a stylesheet per skin. PLT.C in JSR-168/JSR-286 he standards did not define well enough which elements the classes should be applied to, so to implement them as needed each skin used by the portal would have to define styles for each PLT.C class selector + every type of element that could conceivably be used with that class selector (to handle slight or major differences in how different elements should be rendered for the same class selector). Few skins at this time do this. If you feel that enough people using your portlet will have skins that adequately implement PLT.C, the portlet developer should aim to still define the CSS as described here, so that the skins can be tweaked if needed to customize portlet styling with that skin.
Note: As of Feb 2009, Fluid is assisting uPortal so that the Fluid Skinning System (FSS) will be used in future versions of uPortal.
Additional note: In the sample portlet delivered on the Sun website with the JSR-168/286 specs, it doesn't implement the JSR-168 PLT.C part of the spec, seemingly indicating that it isn't part of the spec, or they just missed it.

Additional Portlet Development Styling Recommendations

* Try not to use elements like &nbsp; or <br> / <br/> or images for spacing. Instead use CSS.
* Try not to use style attribute in the JSP or CSS embedded within the page, except for using the above means of including a CSS file with the portlet as a baseline for styles.
* If CSS is included as part of a library/component used by the portlet that does not meet these guidelines, then either fix it (if applicable) for inclusion in the portlet, or possibly warn the user.

JSR-168/JSR-286 Portal Adminstrator/Skin Developer Styling Recommendations

Finding skins
Just doing the following command will help:
find . -name "*.css"
Some examples of skin locations: * a non-standard (but still acceptable) uPortal 2.x skin location: "uPortal/media/org/jasig/portal/layout/DLM-tab-column/fluid-center/(skinname)/skin/"
* a standard uPortal 3.x skin location: "uPortal/media/skins/universality/(skinname)/")
If you can't find a skin, read your portal's documentation and join a support group or mailing list related to the portal. It is possible the portal doesn't support skinning.
Changing Skin
* If you need to change or add a skin to your portal, see your portal's online or local documentation. The following information is for those that have likely already found the skin's CSS and want to tweak the skin's CSS to affect portlet styles. You can also just tweak the portlet's own CSS file if you want- that is up to you, but in either case, back up the CSS before and after changes!
* Look within the portlet for CSS files that might be used by the portlet, and look at the part of pages rendered in the portlet to determine which elements need to be overridden. If you are lucky and the portlet developer made it easy on you (which is unlikely), you might just be able to either copy and paste their CSS into your skin.. You must use your (online) knowledge of CSS specificity rules to make sure that your modified CSS styles will override those defined in the portlet. Using more id selectors in each overriding style than the one in the portlet is the easiest method.
For example:
.mailportletcontainer h3 { ... }
div.mailportletcontainer h3 { ... }

More Info

For information on CSS specificity there are many resources, but I like this one: *

No comments: