Jump to content

Recommended Posts

  • Moderators

Styling of visual elements.

There are some 280 separate css properties which can be used to style each and every visual dom element. The following statement produces such a list

var styles := browserapi.window.getComputedStyle(Panel.handle);       (280 entries)

If we disregard the properties which have a vendor prefix (-webkit, -moz etc) we still end up with some 230 properties for each visual element. 

And although many of these have default property values, the complexity is just too great to do styling on this level.

Each and every css framework (including Smart) tries to reduce the complexity by a number of measures

  1. group css properties into meaningful categories, 
  2. give these groups meaningful names and 
  3. possibly also rename individual properties
  4. connect groups to visual components
  5. making sure that all groups adhere to application wide values (i.e. primaryBlue is set to "#ebf8ff" in all groups)
  6. eliminate annoying differences in how browsers interpret universal css
  7. do this either static and/or dynamic in code

The way the above is implemented varies wildly across frameworks.

Two examples :

Smart does its standard styling mainly by grouping classes on the level of components (1), giving them component names like .TW3Button (2,4). Every visual component gets this class on creation with 2 additional classes for background and border (4).
So the resulting styling of a button gets defined by <button class="TW3Button TW3ButtonBackground TW3ButtonBorder" ...

The supplied css templates in the Templates directory have a feature which implements application wide setting (5), so f.i. const 'EdgeRounding' will be set to "4px" in all components which use 'EdgeRounding (3)'. 
There also some settings which standardise browser behaviour (6)

Furthermore the rtl has methods to manipulate all classes, groups, properties and stylesheets in code (SmartCL.Css.Classes, SmartCL.Css.Stylesheet (7)

Tailwind CCS. 
This framework is sort of on the other side of the spectrum. It groups css properties in a large numer of very small groups (1,2,3). These groups are almost atomic in nature, so f.i. the 'm-0' class is specified as { margin: 0 }.
It basically does not do any of 4,5,6 or 7
So implementing a button using Tailwind involves many classes :

<button class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded" 

which gives a light blue button with rounded corners, becomes a bit darker on hover, has its caption in bold white and has specific values for top/bottom and left/right padding. 

Nevertheless people build beautifully styled apps and websites using Tailwind. And it is readily accessible through code (7)

Thinking about how to merge the best features of the above into a styling design mechanism, I would look at doing this :

1- define a (limited) number of atomic groups. An atomic group combines and names simple css properties which can be used in more complex structures. Candidates are : colors, borders, backgrounds and fonts to start off with. The font-category f.i could be sub-grouped in 'families', 'sizes', 'weights', 'letterSpacings' and 'lineHeights'.  As an example the 'lineSpacings' subgroup could then be specified as

  "letterSpacings": {
    "tighter": "-0.05em",
    "tight": "-0.025em",
    "normal": "0",
    "wide": "0.025em",
    "wider": "0.05em",
    "widest": "0.1em"


2- define generic building blocks or component groups, i.e a generic button, using as many of the atomic groupings from 1) as possible

 "button": {
     "cursor": "pointer",
     "fontSize": "100%",
     "lineHeight": "inherit",
     "backgroundColor": { "colors" : "primary" },
     "border": "none",
     "color": "white",
     "fontWeight": "bold",
     "borderRadius": { "radii" : "default" },
     ":hover": {
       "backgroundColor": { "colors" : "primaryHover"},

This uses the atomic 'colors' group, which will have entries like

    "primary": "#2b6cb0",
    "primaryHover": "#2c5282"

which then will be substituted in the above, so f.i. the 'backgroundColor' entry will become "backgroundColor": "#2b6cb0"
This way all groups who use 'colors:primary' will have the same colour value, application-wide.

3- define descendants from the component groups from 2), f.i. a rounded pill button, which only has those properties different from its parent
  "buttons": {
      "pill": {
        "borderRadius": "full",

So far the above examples boil down to something like this after substitution (2) and child creation (3) 

theme01.colors.primary: #2b6cb0
theme01.colors.primaryHover: #2c5282

theme01.buttons.generic.cursor: pointer
theme01.buttons.generic.fontSize: 100%
theme01.buttons.generic.lineHeight: inherit
theme01.buttons.generic.backgroundColor: #2b6cb0
theme01.buttons.generic.border: none
theme01.buttons.generic.color: white
theme01.buttons.generic.fontWeight: bold
theme01.buttons.generic.borderRadius: 0.25rem
theme01.buttons.generic.hover.backgroundColor: #2c5282

theme01.buttons.generic.pill.borderRadius: 9999px

and a class invocation like <button class="buttonPill ..."  (or even TW3Button)

4- generate this into a regular css template and include the modernize.css entries to harmonize across browsers as well.

5- integrate this in the visual designer

Actually the style generation should closely follow the hierarchy in the visual designer. So if there is a rounded-button on a panel on a form on the <body> element, then the css property values should reflect the #body, #form, #panel, #generic-button and #rounded-button properties (and nothing more).

just an idea, but doable

Link to post
Share on other sites
  • Moderators

Looking into this idea a bit further.

So the ultimate styler program needs to do this :

- read in a theme file
  - discover the visual components in the theme
  - and populate them for use
- have a canvas where these components can be dropped on
  - and can be manipulated qua size and position
  - and have a preview for how it looks in real life

Basically this is an exercise in elevating css to its maximum capabilites, without using js (pascal) or html at all in the styling process.

A first draft of such a program :
The demo theme file contains components for buttons and images, and thus these are displayed on top.
These can be dragged onto the canvas and positioned at will. The coordinates are displayed on the right, either in absolute or relative values. 
The preview icon on the canvas opens up a new live browser window.


So far so good.

The huge number of atomic css properties per visual component (280) now has been subdivided in 3 chunks :

A- those css properties to do with visual design : x (left), y (top), width and height
   These are displayed on the right

B- those css properties which are part of the theme file for this component
   so if for instance the theme file has a line like this: "theme01.buttons.generic.fontWeight: bold", then this will result in a modifier on the screen, where 'bold' can be changed.  <to do>

C- the remainder of the 280 css properties (280 minus A minus B). 
   Those are either not important, have passable default values or are only seldomly important for styling of the particular component. <to do>

Using components ultimately translates into html. 
Taking this example : 

<img class="img" id="Component38" src="images/buttons.jpg" name="button" 
     style="visibility: visible; display: inline-block; position: absolute; overflow: auto; 
            left: 350px; top: 10px; width: 82px; height: 34px; cursor: pointer;">

Styling through css results in modifying the style attribute (.. style="visibility: etc...)

Still debating whether the other attributes should be part of the styling process.
In the demo above for instance I've assigned the 'src' attribute of images to a random unsplash picture, instead of making it directly editable. Its not a css property after all.

Demo here (alpha version)


Link to post
Share on other sites
  • 2 weeks later...
  • Moderators

Digging in a bit further, see previous posts in this thread.

I've set myself the task to define a workable styled css-only component : a slider.

The structure is reasonably simple : in xml terms it will be


The rail is an element which takes up the top half of the slider, with a bottom border color. The knob is an element with a border radius of 50%, which makes it a circle.

The theme file for this component looks something like

  // slider
  theme01.slider.height: 100%

  // slider rail
  theme01.slider.rail.height: 50%
  theme01.slider.rail.border-bottom: 1px solid red

  // slider knob
  theme01.slider.knob.background-color: red
  theme01.slider.knob.height: 2em
  theme01.slider.knob.width:  2em
  theme01.slider.knob.left: 0%
  theme01.slider.knob.top:  -1em
  theme01.slider.knob.border-radius: 50%

This contains enough information to be able to construct and style a slider component on the fly.

To make it a bit more interesting, I've added movement capabilities by adding a compiled procedure as a string :

theme01.slider.knob.function01: onmousedown = function (e) { var saveX; saveX = e.clientX; Self.handle.onmousemove = function (e$1) {

which can be just eval-ed at runtime. This function simply manipulates the 'left' property of the knob.

So here we go, a working slider component from a theme file only. (the complete theme-file here).

And since it does not have any absolute dimensioning info, it resizes automatically to its container.



Link to post
Share on other sites
  • 2 weeks later...
  • Moderators

Off topic : there is an interesting effect when putting images on top of images.

Take an image and give it a large width and height. Take the same image (same src) and place it on top of the first image, give it same height but say 25% of width and center it. Both images should have object-fit set to 'cover' and reduce opacity of the first one to about 65%.

Depending on the image, about 1 in 5 give a passable interesting result doing this, 1 in 50 look amazing.

Some examples here

(not optimised for size, so slow loading)



Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Create New...