Feature Proposal: Remove hardcoded CSS class names

Motivation

Enable proper Foswiki theming.

Description and Documentation

Proper theming is best done through CSS framework such as the one offered by JQuery UI. However using such a framework requires CSS class names used by Foswiki to be customisable instead of being constant.

Examples

Hardcoded CSS class name can be removed from TablePlugin through usage of CssPlugin. Such a prototype was package as TableTmplPlugin.

Impact

TablePlugin, TOC, Some Form field plug-in.
edit

Implementation

-- Contributors: StephaneLenclud - 22 Apr 2009

Discussion

Please add to the documentation on CssPlugin - and to this topic so that others have some idea of why, what and how you are doing/intending to do

I suspect you're doing (and proposing) something very worthwhile, but I have no idea from what you've written.

-- SvenDowideit - 23 Apr 2009

If you write 'hardcoded class names' it sounds like unflexible bad written code. Isn't it the purpose of css files to change the appearance?

If you remove class names, by what is it replaced?

Can you provide an example I can read here without having to install 2 plugins?

-- ArthurClemens - 23 Apr 2009

I suspect Stephane is talking about replacing foswikiAlert in code with $Foswiki::cfg{CSS}{ClassNames}{Alert}.

Not sure I fully understand the value of that. Though I suppose if you have an existing CSS library and want to use it with Foswiki it would save you having to go through a mapping step.

-- CrawfordCurrie - 23 Apr 2009

Crawford is right. The idea is to move as much as possible of the CSS class names into the configuration. Thus I can skin my Foswiki by simply changing my class names in the configuration and actually write very little CSS myself. So constant class names are replaced with variable class names.

For instance right now I can't easily skin input field in data form edition because foswikiInputField is hard coded in lib\Foswiki\Form\Text.pm. My only skinning option is to implement .foswikiInputField in mystyles.css. If I could simply change the input field class through configure from foswikiInputField to JQuery UI ui-widget-content then I don't have to get involved with coding CSS myself. I just make use of an existing CSS framework.

You can diff the Core.pm from TablePlugin and TableTmplPlugin to see the kind of changes involved. For TablePlugin I also added a few variable class names for th and td for instance. Thus I don't have to duplicate the nice CSS the JQuery UI guys have implemented to apply it to a th element, I only give the th element the ui-widget-header class.

I'll try to provide demo URLs soon.

-- StephaneLenclud - 23 Apr 2009

I misunderstood the change at first... Now I would say this need rethinking. This may be a knee-jerk reaction, but I have several reasons against the change as it stands today:

SL: The current implementation is of course just a prototype. The final implementation as yet to be discussed if we agree on taking CSS class names out of the perl code.

  • It will impose yet-another-dependency in the core (CSSPlugin).
  • SL: That particular implementation is just for me since I need that functionality anyway whether it goes in the core or not. Something like $Foswiki::cfg{CSS}{LogicalClass}{Alert} would do just fine if we put that in the core. Add also a short macro for skin to use.
  • Theming the base skin is tedious already, but at least I know that I need to have a "foswikiAlert" style that is used for alerts. With this change, I would have to remember to change the configuration. Given that there are a lot of foswiki classes, the configuration will be tedious, at least.
  • SL: What I'm suggesting does not prevent you from skinning the old (hard) way. For backward compatibility default config can use current class names. It has next to no performance impact.

  • To change the theming, several config options would need to be provided. Same thing about tediousness.
  • SL: Same: you don't need to change the logical class names. You can just skin like before if you want to.

  • To maintain a themes, anyone must take the work to understand where each class is used. This work must be done for each theme that does not use the same classes (you like JQuery, I like YUI).
  • SL: Whether you skin by implementing CSS files yourself or by changing logical class name you need to understand which UI element you are changing. I don't know YUI but if they define CSS classes then the logical classe names are your friend cause it will all you to make foswiki use them

  • The mapping between a foswiki class and the theme-required class is not always one-to-one.
  • SL: One logical class can be mapped to 0..n CSS class names. For instance =$Foswiki::cfg{CSS}{LogicalClass}{Alert}='ui-state-error ui-corner-all'=

To make our lifes easier, perhaps it is best if we just decide that we're going to marry one of the UI frameworks for the core skin(s), SL: Trouble is that hardcoded class names are not part of the skin. They are part of the core and perl code. It limits what the most talented and motivated skinner can achieve. Class names belongs to the skin not to the perl code. Yet using skin templates for something as flexible as TablePlugin is rather tricky if not impossible. So using logical class names from config seems like a good compromise in this case.

-- RafaelAlvarez - 23 Apr 2009

Thanks for the feedback Rafael I commented inline. Hope you don't mind.

I also want to add that usage of logical class names from perl code should be limited. I find we rather introduce new template file where needed. It might be doable with the TOC for instance. In fact template files provide much more flexibility than logical class names. Then it's up to the skinner to decide whether or not he wants to make his skin themeable through usage of logical class names.

Now that's outside the scope that proposal but I thought I would make that comment here anyway. Rafael mentioned "Theming the base skin is tedious already". I find it at least tedious wink IMHO we have way too many class names and div all over the place. I understand it was done like that to provide more flexibility in the skinning but all it seems to achieve is make skinning a nightmare. It is also I believe the reason why our UI is often not consistent and hurts the eyes. Too many fonts, too many colours, too many styles resulting from too many class names and hundreds of lines of CSS code. If you think about it thoroughly there not so much UI components on a web site, not as much as the number of foswiki CSS classes anyway.

I've also developed a skin prototype making use of logical class names ( CssPlugin ) and using JQuery UI. I have to say it's really impressive to be able to change the theme of that skin using the JQuery UI theme selector. Some of you have seen it already from the IRC. I'll publish it soon and provide demo URL. Based on that common concept of logical UI component I'm also developing IconPlugin which is providing skinners with logical icons.

-- StephaneLenclud - 24 Apr 2009

mmm, ok, now that you've explained what you're trying to achieve, I'm pretty sure you're reaching for the wrong solution completely.

imo, all output's should not be anywhere near the code, or cfg. The typically good abstraction is to push them into the templating system, and the proposed solution goes further away from that ideal, not closer.

SL: I agree that we should use skin template as preferred solution to get ride of hardcoded CSS class names. That's already mentioned above. But I believe that's not possible for TablePlugin without compromising on functionality and we don't want that.

Worse, by changing the core css classes, you break an API contract made with application designers - for eg, foswikiSubmit should (and is) be able to be used in Contribs...

SL: Already tried to address that point in my answers to Rafael. Logical class name precisely means that you don't have to change existing class names. It gives you transparent backward compatibility.

-- SvenDowideit - 24 Apr 2009

I am not completely convinced that the proposed solution is either right or wrong.

As a web designer and web app writer I do know that there is a constant need for css classes and specific styling for specific widgets. When creating new markup you are in the situation having to know the semantics of all existing css classes and reuse them as far as possible. If there is no class that matches your new markup or it only nearly matches your intended semantics, you ultimately will have to introduce new css classes. And these are introduced in the topics your web app is made of. People that write those apps don't necessarily have access to either use perl, the template system, configure or any webpreferences topic. They are just normal wiki users with an extra portion of web app intuition. Some add-ons come as a bunch of topics only.

From what I see in this proposal, the extra abstraction layer can only be used to cover standard html markup as it is emitted by the template system and the core. But that's pretty much where it stops, as far as I can see. The effect of this is that you will have the best/worst of both worlds: abstract and non-abstract css classes will coexist in foswikis. This seems to complicate things more than abstract classes help.

For now the agreed informal standard is that those components of the system (core, plugins, web apps, ...) introduce css classes using a prefix to the name that indicates where this css class comes from, e.g. foswikiXXX are owned by the core and so on. As a web designer you will always have to learn the markup and the css classes you have got at hand and style the stuff to your needs. In that sense you will have to deal with extra plugins and extra css your theme has to cover. So instead of bowing css classes towards a specific framework that a designer prefers, he is doing much the opposite by adding extra coverage in his style sheets.

But I see you don't want to get into the role of a web designer here but still deal with css namespaces in sensible way.

I can see where the motivation for this proposal comes from, i.e. being able to create a skin that makes use of JQuery UI theme rolling, but you don't want to patch the core to remove hardcoded foswikiXXX classes and you don't want to write a new skin. Both is absolutely understandable. Therefore introducing a css mapping seems to be your next logical step in your approach.

Again, I can totally follow your reasoning and think that this is worth exploring in more depth. Best for you to proceed is to create an experimental branch in SVN under SCRATCH and continue your work there to (a) flesh out your findings addressing the concerns raised here and (b) convince the rest of us.

SL: Thanks for the feedback Michael. Very encouraging. I think you understood my motives very well. I'll definitely try to consolidate everybody's concerns and see if we can come to a solution that makes everyone happy.

-- MichaelDaum - 24 Apr 2009

As I understand it the problem Stephane is trying to solve is this: Given an imported CSS, it is impossible to use it with Foswiki without changing class names, either in the code or in the CSS. By creating "virtual class names" Stephane hopes to effect this mapping in the code.

SL: very well explained

On a simplistic level this is a problem that bites anyone who tries to reuse CSS, written for another application, at some point. It's a basic limitation of CSS that it doesn't offer any way to assign a new name to an existing class. On a more realistic level there are significant issues with re-using CSS, because the semantics of the classes rarely map perfectly from one application to another.

SL: It seems quite realistic to me. I have a well advanced skin prototype that fully supports JQuery UI theme roller. Again: I'll publish it very soon. It is often available for demo from the IRC in the evenings.

There is another potential solution to this problem that hasn't been explored, and that is to map the CSS class names using Javascript. A generic "CSS class name mapping engine" could be an interesting tool for those of us who are prepared to use JS.

SL: I don't like heavy JS solution for doing that as it will put more strain on the client and I like to use weak clients (phones).

-- CrawfordCurrie - 24 Apr 2009

Thank you all for the feedback. From reading your comments it seems that most of us agree that CSS class name don't belong to the core but rather to the skin. Some made the point that they don't belong to the config either but again to the skin. We could then think of a cssclasses.tmpl to implement logical class names. So each template DEF would be a logical class name.

JQuery UI flavor:

%TMPL:DEF{css-class-alert}%ui-state-error ui-corner-all%TMPL:END%
%TMPL:DEF{css-class-button}%fw-button ui-state-default ui-corner-all%TMPL:END%

Foswiki default template:
%TMPL:DEF{css-class-alert}%foswikiAlert%TMPL:END%
%TMPL:DEF{css-class-button}%foswikiButton%TMPL:END%

Note the ccs-class prefix to make sure those DEF don't conflict with existing DEF from other templates. It seems heavier to implement than the config option but it is probably better conceptually. I would have a plug-in or core component loading that template and providing easy access to logical class names from the code and from the skin and topic level.

Access from the code could be done through a new API:
my $actualAlertClass=Foswiki::Func::CssClass('alert');

Access form skin templates and topics could look like:
%CSS{'alert'}%

Note that we don't use the css-class prefix there to make the syntax more compact.

-- StephaneLenclud - 24 Apr 2009

Added myself to ConcernRaisedBy to prevent this getting accepted automatically after two weeks. Don't misunderstand this as a fundamental disagreement. It simply needs more time to be UnderInvestigation, I guess.

-- MichaelDaum - 24 Apr 2009

CSS class name don't belong to the core but rather to the skin - absolutely. I would be in favour of anything that lets use decouple class names from the core code. To be honest I'm in favour of anything that lets use get HTML - and it's use of CSS - out of the core code, because it makes a mockery of the concept of "templating".

So I'm going to add myself to the concerns list as well, for the same reason as Micha. This needs a lot more thought, the current proposal isn't refined enough.

-- CrawfordCurrie - 24 Apr 2009

True! HTML does not belong to perl code either. Strictly speaking things like CGI::table should not show up in our perl code. In fact when I started taking care of TablePlugin my initial intention was to use skin templates and therefore take both class names and HTML into the skin. If you compare TablePlugin with TableTmplPlugin you can even see the template loading code I commented out. However I found full templating of TablePlugin quite challenging if you don't want to loose functionality. Knowing I needed to do minimum changes to TablePlugin to make them acceptable for the community I came up with the logical class name idea.

Wherever reasonably possible we should simply introduce new skin templates to remove hardcoded CSS and by extension HTML from the core. However logical class names are still worth having to deal with TablePlugin and possibly a few other places in a backward compatible way. On top of that, if used by a skin and consistently across the platform they provide unprecedented skinning efficiency and flexibility.

-- StephaneLenclud - 24 Apr 2009

Here is the promised demo, make sure you play with the theme selector pop in the top right corner of those pages:

That installation is running 1.0.5beta1 with TableTmplPlugin, JQueryLibPlugin, CssPlugin, SoftSkin, IconPlugin (very early draft). Apologize for the poor documentation on those plug-in pages but I have the bad habit of not starting by writing the docs when I implement a piece of software.

-- StephaneLenclud - 24 Apr 2009

After some thoughts, now I know what really bothers me: it is not possible to create a new abstraction for a domain problem that is not well-known unless you have at least two concrete solutions.

I understand the motivation, and this already explored from the JQuery angle. I would like to see it explored from other angles:
  • A YUI based skin
  • A L&F that is being migrated to fosiki from an existing application *

So I support fully that this should be on a scratch branch to experiment.

And I still think we should make our life easier and decide to use a UI Library for the "core".

-- RafaelAlvarez - 25 Apr 2009

Some fair points. I'll never find the time to experiment and play around with three CSS UI framework though. Slight precision: Perl core should not have to choose a UI framework, only the default skin does. But that's outside the scope of that proposal. What I would like to drive here is the perfection of the core and default plugin skinability by removing as much hard coded HTML and CSS as decently possible from there.

-- StephaneLenclud - 25 Apr 2009

I've modified TableTmplPlugin and CssPlugin as explained above so that we are now using skin templates to load the class names. See http://www.slion.net:8080/Sandbox/TestTopic again. The result can notably be seen in the table source when looking at http://www.slion.net:8080/Sandbox/TestTopic?skin=pattern. Before it was still showing the JQuery UI CSS since they were loading from the configuration. Now it shows default pattern skin / foswiki CSS.

The table colours look broken with pattern skin because I've changed the default hardcoded settings from TablePlugin to make sure it does not inline CSS code in the HTML. CSS within HTML code is to be banned too to enable proper skinning. Instead pattern CSS style should be extended to skin the table too.

Hope you like that solution better. Now you can argue that we don't want platform wide logical CSS class name cause it's totally overkill for solving our issue there. I can understand it scares some even though I'm convinced designing our new default skin using this solution would be greatly beneficial. Then I can make that class skin template solution specific to TablePlugin in order to make it skinnable .

I guess I should close this far too generic proposal and open component specific ones starting with TablePlugin then TOC and whatever else needs to be skinned.

-- StephaneLenclud - 25 Apr 2009

I think you've continued in the 'wrong' direction. I/we? wasn't suggesting that the css class names be tmpl:def'd, but rather that the entire output html (css included) be extracted into templates.

there was a work done a few years ago that replaced our hand coded template code with TT2 (see tmwiki.org) - that is the kind of thing we really need - to abstract the CGI and hard coded html with getTemplate('tableHeadding') like abstractions.

-- SvenDowideit - 28 Apr 2009

I second Sven's comment.

-- CrawfordCurrie - 28 Apr 2009

In an ideal world (here CSS3 support from the browsers was complete and reliable) I would say that the proposal goes the wrong way. The spirit of CSS is that the class names be fixed to express semantics by the code, and the job of the CSS authors and frameworks is to "style" these given class names. Introducing flexibility in the class names in the code is the wrong way to solve this problem as it will reivent inconsciously yet another new templating system.

In the real world, CSS as it is implemented, is not complete enough to allow decoupling style from structure. I thus second Sven comment: please let's not reinvent the wheel, and rather reuse a standard way to separate style from structure: template engines. So Stephane, your goal is nice, but please select a template engine to achieve it.

-- ColasNahaboo - 28 Apr 2009

I agree that in an ideal world the whole HTML should be taken out of TablePlugin. However as mentioned above it's a lot more work than simply templating the CSS class names especially if you want to make it backward compatible. I guess I was just aiming at making an easy fix to bring flexibility in a backward compatible way to TablePlugin. That's called compromising wink We probably don't even need to bother I'll just use my TableTmplPlugin until we support TT2.

However it's going to be harder to manage on my own when I need to customize thing that the core itself output (rather than a default plug-in).

TT2 sounds like a lot of fun, I'm sure that's the way to go.

-- StephaneLenclud - 28 Apr 2009

I see no more drive for a consensus on this. And there is massive concern and noone supporting. Taking this to a vote would probably mean rejection.

So do we declare this dead?

Or does Stephane want to raise a compromize proposal with a new spec?

-- KennethLavrsen - 22 Feb 2010

parked - we're hoping to go a different route.

-- SvenDowideit - 06 Mar 2010

See Compass (using Sass) for a possible route.

-- ArthurClemens - 06 Mar 2010
Topic revision: r31 - 22 Sep 2010, WillNorris
The copyright of the content on this website is held by the contributing authors, except where stated elsewhere. See Copyright Statement. Creative Commons License    Legal Imprint    Privacy Policy