Maintainable CSS

I have found Maintainable CSS site exceptionally useful for designing maintainable CSS systems.

Modular and encapsulated: Styles don’t bleed or cascade without your permission.

Any design requirements: Completely flexible to your needs.

No tooling required: But you can use tooling if you want to.

Easy to learn: Read the guides and see.

Any size project: Whatever size project you have, MaintainableCSS will help.

Upgrade in your own time: You can start applying the approach today, bit by bit. You don’t need to upgrade the whole

Tokenizer + ::mark() = syntax colorizer

Here is selfie of syntax (tiscript) colorizer – the text below is a full source code of syntax highlighting routine.
The code has colorized itself:

syntax colorizer
syntax colorizer

Can your browser do that in 40 lines of code?

And here are styles that define style of tokens:

plaintext > text::mark(number) { color: brown; }
plaintext > text::mark(number-unit) { color: brown; }
plaintext > text::mark(string) { color: teal; }
plaintext > text::mark(keyword) { color: blue; }
plaintext > text::mark(symbol) { color: brown; }
plaintext > text::mark(literal) { color: brown; }
plaintext > text::mark(comment) { color: green; }

Easy, no?

And even shorter selfie, colorizer wrapped as an aspect component (referenced from colorizer.css):
colorizer

::mark(…) feature is comming

Please consider these tasks:

  1. Find all words in text on HTML page and highlight them
  2. Syntax highlighting: parse text of <pre> and mark all keywords by changing their color
  3. Find all misspelled words in <textarea> highlight them specifically.

Currently you can do #1 and #2 by wrapping each text found into <span>s with specific classes – thus to modify DOM structure of the document. Such modification by itself is a) not trivial to implement, b) is highly non-desirable (consider text editor with syntax highlighting) and c) even impossible in case of <textarea> for example.

Ideally we should have some facility that will allow us to a) mark text fragments, b) apply styling to such marked runs through CSS and c) do that without DOM tree modifications.

As a result upcoming Sciter will have:

  1. In CSS, support of ::mark(...name[s]...) pseudo element.
  2. In script runtime, new methods of Selection class:
    • Selection.applyMark(start,end, ... mark names...); – to add marks to the range.
    • Selection.clearMark(start,end, ... mark names...); – to clear marks from the range.

Example, CSS:

div::mark(hilite) { background-color:lime; } 
div::mark(hilite2) { background-color:cyan; }
div::mark(literal,string) { font-style:italic; color: red; }

First rule will tell the engine to set background color on all text runs that are marked by “hilite” to “lime”.

And script code

      var text = $(div).firstNode;
      var start = [bookmark: text, 6, false];
      var end   = [bookmark: text, 11, false];
      Selection.applyMark(start,end,"hilite");

will apply mark “hilite” to the text node from 6th until 11th position and so you will have the following rendering:
marks in text nodes
Note: this will not change DOM structure but rather apply some meta information to characters in the text.

In Sciter <frame> element may have content-style attribute defined.

That content-style attribute takes URL of style sheet that gets applied on top of existing styles of the document:

<frame src="some-child.htm" content-style="content.css" />

That content.css gets appended to the list of other styles of the some-child.htm as if that document has <link rel="stylesheet" type="text/css" href="content.css"> at the end:

<html>
<head>
  <style>
    ... local styles ...
  </style>
</head>
<body>
   ... local content ...
</body>
 <link rel="stylesheet" type="text/css" href="content.css">
</html>

So when host document wants:

  1. to customize rendering of child document in the frame
  2. and/or inject some scripting behaviors in it

it can provide its own content.css file without the need of that child element modification.

Sciter SDK built-in document browser is an example of content-style usage:

{sciter-sdk]/doc/main.htm defines content frame as:

<frame #content src="content/preface.htm" content-style="styles/content.css"/>

so each document loaded into the frame gets {sciter-sdk}/doc/styles/content.css applied to its content

display:none is considered harmful

Quite often in HTML/CSS based UIs we need to hide/show some elements in runtime.

Probably the most widespread (and the worst) solution is to set display:none CSS property programmatically.

That sounds quite easy at the first glance but solves only half of the problem – it hides – removes the element from rendering tree. But what you would do when you need to show element that was previously hidden that way? Setting it to display:block is very wrong. Far not all elements have display:block model by default in HTML.  <img>, <input>, <select>, <textarea>, etc are display:inline-block. <table> and all its children have special display:table**** values. Setting them to display:block will lead you to quite surprising results.

Therefore in order to use display:none in runtime you will need to know original display value of the element. Not quite convenient and maintainable. Imagine that your web designer (probably sitting on other continent) decided to replace some elements horizontally by declaring display: table-cell on them. You will get problems hiding/showing such elements by switching display: none <-> block.

To overcome such a problem jQuery for example implements its hide() method by storing existing display value to special property named "olddisplay". And restores the display from that property when you need to show the element. That approach is far from ideal either for obvious reasons.

Better solution

Better solution is to use attribute "hidden". So instead of setting element.style.display CSS property you will need to add attribute "hidden" to the element when you need to hide it and remove that attribute when you will want to show the element. In order this to work you will need to add single and simple rule to your stylesheet:

[hidden] { display:none !important; }

If some elements need to be hidden by default you will use hidden attribute in your markup, for example as:

<button id="ok-button" hidden>OK</button>

In Sciter you can define some virtual property, e.g. "shown", to all DOM elements (in some common "utilities" module):

/* CSS must have [hidden] { display:none } rule in order this to work */
property Element.shown(v) 
{
  get return this.style#display != "none";
  set this.attributes["hidden"] = v ? undefined : true;
}

and use it as

var someEl = ...

someEl.shown = true; // to show
someEl.shown = false; // to hide

The solution is not free from obvious drawbacks though:

  1. you need that special [hidden] { display:none; } rule to be present in your CSS and
  2. In all cases when you need to hide/show the element you should do it either through that special "shown" property or explicitly by removing "hidden" attribute from the element.

visibility:none

Since Sciter version 3.1.0.15 you can use visibility:none; in CSS to exclude the element from rendering. Exactly in the same way as display:none;. It has exactly the same effect.

As the visibility property is orthogonal to the dsiplay you can safely assign "none" and "visible" property to it without affecting display model of the element.

Therefore, the visibility property in Sciter can accept following values:

  • none – the element is excluded from rendering tree in the same way as display:none, that is Sciter specific;
  • hidden – the element is in rendering tree, takes space but not rendered;
  • collapse – the element is in rendering tree, takes space but its height or width is collapsed to zero. E.g. in flow:horizontal container visibility:collapse child will take space vertically but rendering width will be set to zero. In Sciter this will work for any elements but in standard CSS only for table rows for some unknown to me reason.
  • visible – default value, element is rendered normally.

And here is modified version of the shown scripting property defined above:

property Element.shown(v) 
{
  get return this.isVisible;
  set this.style#visibility = v ? "visible" : "none";
} 

Context menus in Sciter

Context menu is a standard UI feature and in order to support them Sciter has following mechanisms on board:

  1. custom CSS property named context-menu. It defines location of DOM element ( usually it is one of <menu class=context> ) that will appear on context menu activation.
  2. Menu behaviors and their DOM events associated with menus.
  3. Context menu activation and initialization mechanism.

Continue reading “Context menus in Sciter”

Sciter. Declarative behavior assignment by CSS: ‘prototype’ and ‘aspect’ properties

From the very beginning Sciter supported declarative scripting class assignment to DOM elements.

If you want all div.some-widget elements in your document to behave in some special way (be subclassed) then you will need:

1. in script to declare

class SomeWidget : Behavior {
  function attached() { ... } // called with 'this' set to the DOM element 
                              // being subclassed on DOM construction
  function detached() { ... }
  // ... SomeWidget specific methods here
}

2. and in CSS to declare

div.some-widget { behavior:SomeWidget; } 
/* or if SomeWidget id declared in other file: */
div.some-widget { SomeWidget url(some-widget.tis); }

After that all div elements having class=”some-widget” will have SomeWidget class assigned to them. I have explained this mechanism 8 years ago (time is passing, yes) here.

This works reliably and is quite convenient.

The only problem with behaviors/prototypes – at any given moment of time particular DOM element can have one and only one scripting class. JavaScript and TIScript do not support multiple inheritance.

Imagine that you have multiple functions in script aimed to configure some DOM element to serve some specific functionality.
In other words each of such functions adds its own aspect (partial functionality) to the element it is called on. Like:

function addClickHandlerFor(element) {
  // adds onClick handler defined by "click" element attribute in html
  element.on("click", function() { 
    var attrClick = element.attributes["click"];  
    element.eval(attrClick); // evaluate the expression
  });
}

You can have set of such functions configuring different aspects of elements/behaviors.

This works in principle but you will need to call such functions explicitly for all elements for which you will need such configurations. And don’t forget to call them it for content created dynamically (non-trivial task by itself).

Considered all these I have introduced new ‘aspect’ Sciter specific CSS property.

The aspect CSS property

It is declared as

  aspect: "function name" [ url(of-function-implementation-file) ];

Where "function name" is fully qualified name of the “aspect” function that is aimed to configure/setup some additional functionality on the element. And the url() is file name where it is defined.

Principles of aspect handling:

The “aspect” function is an ordinary tiscript function that gets called

  1. with this set to the DOM element satisfying the CSS rule.
  2. strictly once per life time of the DOM element.

And yet, the aspect CSS property uses non-standard inheritance – if the element has multiple matching rules with the aspect defined the used aspect is a list of all aspects. Thus if you have have these rules (example taken from the Plus engine):

[click] { aspect:"Plus.Click"; }
[dblclick] { aspect:"Plus.DblClick"; }

and the element defined in markup as

<b id="clickable" click="..." dblclick="...">text</b>

It will get two calls – Plus.Click() and Plus.DblClick() for it. As if you have the following in your CSS:

#clickable { aspect:"Plus.Click" "Plus.DblClick"; }

The aspect mechanism is actively used by Plus ( /samples/+plus/ ) and Lang ( /samples/+lang/ ) engines in Sciter SDK.
Plus provides declarative data binding facilities “a la” AngularJS and Lang is about i18n support.

“Theory” of URLs for developers

We are using URLs these days quite a lot, but not all of us understand what they actually are.

By this post I will try to explain their structure and how Sciter/HTMLayout deals with them.
Please note that this is sort of informal explanation and I am using term “URL” here while “URI” is more correct name for that entity strictly speaking.

URLs are made from these 5 major parts:

<scheme name> : [//] <resource identification > [ ? <query> ] [ # <fragment> ]

Where:

  • scheme name – is in principle any name token – name of the URL scheme. Some of names are well known: “file:”, “http:”, etc.
  • // part – if present, means that the following “resource identification” part uses hierarchical naming convention, with ‘/’ character as a delimiter.
  • resource identification – is either ‘/’ separated path name if ‘//’ is provided. Or it is some “flat” name.
  • query part is in principle meaningful only for dynamic client/server scenarios. It is an instruction to the server to provide that resources with those parameters.
  • fragment – is a name or ID of some sort that identifies some location or part inside the resource.

Consider that you have the same HTML test-file.html available from these three locations:

  1. file:///c:/test-folder/test-file.htm
  2. http://example.com/test-folder/test-file.htm
  3. res:test-file.htm

Let’s imagine that the document contains image with relative path:

  <html>
  <img src="image.png">
  </html>

Sciter, while loading the document, will resolve relative path name “image.png” to these:

  1. file:///c:/test-folder/image.png – as base URL is hierarchical one.
  2. http://example.com/test-folder/image.png – ditto.
  3. res:image.png – but here only resource schema is inherited as base URL uses “flat” naming convention.

In principle your Sciter application can use your own URL schema. You just need to decide will it be hierarchical or flat.

For example if you will call SciterLoadHtml(html, "app://module/main.htm"); then all relative links inside that document
will be resolved against app://module/ base name. So in your SCN_LOAD_DATA handler you will get: “app://module/images/img1.png”, “app://module/styles.css” and so on.

But if you plan to put all your files into resource section of your executable then you should use “flat” schema, like “res:”.

And the last note: if you use hierarchical URLs in SciterLoadHtml and SciterLoadFile calls then these urls must be absolute ones otherwise Sciter will not be able to resolve them reliably.