Monday, May 23, 2011

Putting stuff before a counter with CSS and associated caveats

I thought this too important to be passed up, so here's only a very rough draft of what I discovered. And because I was only revisiting this subject right about now, I have yet to get my own head around all this, with more detailed explanations.
(Blogger had nasty issues with updating their software, so a number of blogs were in read-only mode and so instead of writing this up I was occupied with other things. The good thing is that Blogger have been very responsive in addressing the posting outage.)


When tallying personal data and opinions for what was ostensibly a list of items in a text file, I wanted to find out how in an ordered HTML list (a numbered list with <OL> tags) I'd be able to use Cascading Style Sheets (CSS) to place some special items before counters (usually numbers, but CSS 2 standard has expanded counters to be much more) as markers of some sort.

The main point was to make a more informative and interesting list... Well, yes, but this turned out to be a far more difficult exercise than I first thought.

For an intro, the following describes the differences in rendering between Mozilla Firefox 2 and Mozilla Firefox 3+. Because these browsers use the Gecko rendering engine, which is used by other browsers, then here's also a quick browser side-by-side of the rendering engine's branches:
Gecko 1.7Gecko 1.8.1Gecko 1.9 and newer
Mozilla Firefox 1.0Mozilla Firefox/IceWeasel 2Mozilla Firefox/IceWeasel 3+

Mozilla Application Suite 1.7
SeaMonkey 1.1SeaMonkey 2+
K-Meleon 1.5K-Meleon 1.6+

What follows is example CSS code with some comments. I haven't yet had all the time to describe everything, but bear in mind the lede.
OL.Eurovisioon {counter-reset:item; list-style-position:outside}

OL.Eurovisioon LI {display:block;}


/*display:block ^ loses the browser's automatic numbering;
• The items must be displayed as block, so as to make sure that the later width attribute applies. */

OL.Eurovisioon LI:before {float:left; content:'miskitekst\ ' counter(item) '.'; counter-increment:item; border:solid 1px gray; padding-right:5px; width:82px; text-align:right; line-height:1.1em; color:navy; white-space:nowrap} /* these work... */

/* ^ • Floating them left makes sure that the items are displayed like in a standard ordered list;
item must be inside counter(), item is also specified for counter-increment;
text-align:right aligns numbered counters right and so makes it more list-like again;
white-space:nowrap makes sure that when increasing text size, text inside blocks wouldn't wrap and add in height and take away from the structure.

Caveats:
Once the items are all displayed as text-block or inline, the width attribute does not apply anymore. Displaying as block and floating to right works in Firefox 4 (I'm also assuming 3.0+), but not in SeaMonkey 1.1 and anything with the Gecko 1.8.1 engine (see the above table) and the caveat applies to all older browsers.). Setting the display to text-block or inline fixes the issues in SeaMonkey 1.1, only that setting width attributes does not work then. */

OL.Eurovisioon > LI.plus:before {width:82px; content:'\ sisu\ ' counter(item) '.\ '; text-align:right; color:blue} /* somehow works */

OL.Eurovisioon > LI.plus {list-style-position:outside}
^ Is this really necessary?
Moreover, the list already contains tabular data; including informative content with :before or :after pseudo-classes means that this data won't be indexed and may be lost to search engines. Non-graphical and older browsers won't be able to see such content.

I, of course, thought that I'd never see the day when my own fancy CSS implementation would not be visible with something like SeaMonkey 1.1.19.

The correct rendering is supported by Mozilla Firefox and IceWeasel 3 (probably since 3.0), SeaMonkey 2, Google Chrome (Version 11 does, so I'm assuming a host of earlier versions do, too), and the latest Konqueror, Apple, and Opera fare. Internet Explorer 7 does not support this. Bleh.

So here's the example list:
  1. tekst
  2. teine tekst
  3. kolmas tekst
  4. neljas tekst
with corresponding code in HTML:
<OL CLASS=Eurovisioon>
<LI>tekst</LI>
<LI CLASS=plus>teine tekst</LI>
<LI>kolmas tekst</LI>
<LI>neljas tekst</LI>
</OL>
So long I still have to use Mozilla Firefox 1.0, I must still use a simple HTML table. At least the advantage is that most browsers will be able to see the content. The table in question is here.

As the information was laid out in a text file, it nevertheless turned out to be tabular data, which was actually much simpler to organise into a table, rather than implement complex CSS for the same.

Tuesday, May 10, 2011

Collapsing elements in Firefox 1.0

As I was perusing Yahoo Mail Classic in Mozilla Firefox 1.0, it turned out that there was a linked block element half-blocking the sign-out link at the top of the page and in May this year, those links stopped being underlined when hovered over — this made targeting the pointer too difficult to click on the sign-out link. If I click on that block element, it will jump to a position on the page, then, somehow the block element probably moves and probably frees up the space above the sign-out link... Or whatever.

Turned out that the culprit was an invisible non-collapsed block that contained a "Skip to conent" link, which was meant for browsers like Lynx, Links, Elinks, Netscape 4.x, and other older fare (Lynx is still maintained :). This is really the fault of site coders, who instead of specifying display:none in the element's style, only specified visibility:none. The former would have collapsed the whole element, the latter only makes it invisible, but still usable and visually existent in the document structure.

If positioning is important, then one design solution is to specify a low z-index for the invisible DIV element and a correspondingly higher z-index for code that contains links (an unordered list). In CSS, z-index specifies how elements are layered with respect to each other: a higher value means that an element is above (or in front of) all other elements and a lower value (if somewhere is a higher value specified) means that the element is below, or behind higher-valued elements.

First I tried the Adblock Plus (ABP) extension, but that didn't work: ABP 0.7.0.2 is the last version for Firefox 1.0, but lacks functionality to collapse/hide elements by their id. Only the next version, 0.7.1, starts supporting this. I've written about it previously.

As I was looking for a solution, the Greasemonkey extension caught my fancy. The last to support Firefox 1.0 is 0.5.3.
Version 0.5.3 is also the last one of Greasemonkey to install on SeaMonkey 1.1, but it doesn't work.

The solution is to first install xSidebar (If the current stable versions won't want to install, then version 1.0.1 or 1.0.2 might install properly). Then on the back of xSidebar a modified Greasemonkey extension can be installed. So for SeaMonkey 1.1, Greasemonkey 0.8.2 mod is the order of the day. Note that if you have Adblock Plus 1.0.2 installed, its toolbar button will vanish. But no worries: You can turn on the Adblock Plus status bar icon from Tools > Adblock Plus Preferences...
Greasemonkey is a powerful tool to change the look and functionality of online sites and web pages client-side, but alas, it is not very easy and requires knowledge of HTML, JavaScript and CSS.

There are many instructions online on how to incorporate custom JavaScript and CSS snippets into your browser equippped with Greasemonkey and how to specify server whitelists and blacklists. I might introduce the same instructions here or put them up somewhere else.

While I thought I just had the solution, it then turned out that the block element was only equipped with a class parameter and no ID. I had also learned that only recent and modern versions of Greasemonkey now support the JavaScript getElementbyClass functionality, but I only have an outdated version.

Well, no matter: Greasemonkey 0.5.3 supports getElementbyId, but that really is not the most important thing, because Greasemonkey also allows injecting snippets of Cascading Style Sheets with JavaScript. And CSS is power.

Yes, while the DIV element did not have the ID parameter in it, it still had the CLASS parameter specified and the solution looks like this:
document.styleSheets[0].insertRule('A[class~=yucs-skipto-search] {display:none}', 0);
/* ^A is the linked element;
• Square brackets in the selector are used for conditional matching in the form of ELEMENT[attribute=value] — In this case, the {display:none} CSS block applies when yucs-skipto-search is found anywhere in an A tag's class attribute value (which the next point is about);
~= means that the pattern for the element attribute may be any matching part inside class, because when I looked at the source, the class parameter contained more than just yucs-skipto-search.
display:none collapses the element. */

document.styleSheets[0].insertRule('A[target=_top]:hover {text-decoration:underline !important;}', 0);
/* ^ In this line, Any hovered link tag A where the target parameter exactly contains _top must be underlined when hovered over. Note that instead of ~= for any matching part inside A[TARGET ]there is a single equals sign = for an exact match. !important overrides anything provided previously and makes sure that the these links are underlined when hovered over. */
So much for now.

Sunday, May 8, 2011

Adblock Plus and Why Mozilla Firefox 1.5 Matters

Yes, Mozilla Firefox 1.5 is old and outdated, yet it's a notch newer than Mozilla Firefox 1.0. Some people may be stuck with it (when stuck using a Live CD or an older computer with an older operating system). When comparing Firefox 1.5 with 1.0, then it, of course, renders slightly better and with less caveats. For computers with sparse resources, Firefox must still be configured to run efficiently.

And not just: It can handle newer extensions, the greatest of which in order of importance are NoScript and Flashblock, and now add Adblock Plus (ABP). The reason? Some modern (as of 2011) websites now harobur designs that do require collapsing some elements in order to view their pages with some attempted modicum of properness (anything on wikia.com). And Firefox 1.5 is the earliest browser to support a version of ABP that collapses CSS elements by id.

Here's how: Adblock Plus 0.7.0.2 (08.06.2006) is the last to run (to be properly supported) in Firefox 1.0, but most unfortunately, lacks the necessary feature.

The next version (0.7.1), which incidentally first includes the functionality of collapsing CSS elements by their ID, only supports Firefox 1.5 or newer. (But this is not the version of ABP you'll need, if you're somehow stuck using Firefox 1.5.)

The last version of Adblock Plus to support Firefox 1.5 is 0.7.5.5 (01.12.2008).

Thursday, May 5, 2011

Adding formatting to CSS generated content

This solution (or workaround, if you like) came out of a need to write text visible only for modern browsers.

I have a case, where such text would point out a formatting feature containing further information in <ACRONYM> tags, only that severely out-of-date and text-only browsers do not support the dotted underline and border properties, so help text for these browsers was not necessary. I wouldn't use JavaScript (which uses document.write) and there are websites like WordPress (IINM) that only allow editing CSS files and may forbid JavaScript.

The CSS 2.1 specification has it that it's possible to create generated content before or after an element, using :before and :after pseudo-elements, respectively.

The best explanation about how it works is in the CSS2 technical recommendation at W3.

The difficult part is in how to format text within the content: property.

Well, there are two ways that work and a third way that is a workaround. The two ways are well-documented in the W3 technical recommendation (see above link), where it's possible to specify attributes with first-letter and first-line (for longer texts within content) pseudo-elements.

The Third Way

Specifying formatting for bits of text within the content: property is impossible, so the solution is to create one or more rulesets of :before or :after pseudo-elements with similar declaration blocks, wherein some rulesets' declarations are different.

In HTML, write the following snippets of code:
<SPAN CLASS=text></SPAN><SPAN CLASS=dotted></SPAN><SPAN CLASS=bits></SPAN> and so on...
In CSS, example code shows the following:
.text:after {content:'^ Mouse over text with\ ';}
.dotted:after {content:'dotted underlines'; border-bottom:dotted 1px; border-bottom-color:inherit;}
.bits:after {content:'\ for more infobits'}

/* ^ Use the backslash \ to escape special characters, including a space (or it won't be shown). */
The result:
Browsers, which don't support CSS :before and :after pseudo-elements, won't see this. ^

The result is used here in a previous blog post. The example text snipped was put in place of a paragraph break, but since the Lynx browser wouldn't create a paragraph break inside a list with <P></P> or <BR><BR>, or instead there was more space added in modern browsers with variants that included a non-breaking space &nbsp;, then the best solution was to wrap above HTML code within <DIV> tags and add a non-breaking space —
<DIV>&nbsp;<SPAN CLASS=text></SPAN></DIV>
Characteristics
The most interesting and equally obscure characteristic with CSS generated content is, that generated text cannot be directly copied — even when selecting a normal area that wraps around generated content, then only the wraparound selection is pasted.

While this may be useful to wonks interested about protecting original content, then it's still a chore to implement, and advanced users would still be adept at copying text from near the source (unless obfuscated). The technique is similar to mechanisms that disable direct text copying in advanced document files, like PDF, but with the difference in sophistication: PDF files have encryption and other features.

The (dubious) advantage is, that direct copying is disabled; and the disadvantage is, that a number of browsers don't support these pseudo-classes. And not just older (Netscape 4) and niche browsers (Lynx, Links, Elinks), but even Internet Explorer 7 doesn't.

16.12.2015. Update:

I recently wanted to add newlines to generated content, but after several turns of trial-and-error with \A in content:, I turned to a search engine and found about the best blog post by Chee Aun that describes the issue in detail.

The solution with Firefox is to specify white-space:pre-wrap — This preserves both wrapping and newlines.