/ Development  

The power of Less - A CSS-preprocessor that will boost your stylesheet

Hi there AppWorks fans,

Welcome to a new installment of AppWorks tips.

For this post we dive into the 20% of knowledge to start with something cool. Why 20%? Well, that should be sufficient to trigger our mindset and creativity to use this language somewhere in the future. I was not aware that “Less” was an option on the AppWorks platform until I did a little resource on the ‘Theme’ type of document…Interesting stuff, but what is a CSS preprocessor (what “Less” is!)? Well, simple! It makes your CSS stylesheets dynamic, you can build logic in a stylesheet, and you can write less 😜 CSS. What you write in “Less” will eventually generate to a real CSS stylesheet in runtime; that’s why it’s called a pre-processor.

What this post is NOT: A “Less” tutorial; There are more advanced tutorials on the interwebs. This is my list of resources:

Just for you to know: Next to “Less”, you will also find Syntactically Awesome Style Sheets (Sass) as CSS-preprocessor; I leave it out of scope for this post (the platform does not use it as far as I could see), but has a similar mindset!


Let get right into it…

First of all,…”Less” stands for: Leaner Style Sheets, but where can we find “Less” on our AppWorks platform? Well, dive into your solution (or create a new one). From the folder structure, create a folder with name theme, and create a new document of type ‘Theme’ with a fancy name thm_main. From this document, you can dive into the ‘Advanced’ tab where we’ll see our first “Less” language lines of code. Here is a copy of the default generated code on my AWP 22.3 environment. When you publish this new ‘Theme’ document, you will find the result in runtime behind this URL: http://192.168.56.107:8080/home/appworks_tips/themes/custom.css

So, what oddities do I (as non-CSS-guru-but-understand-it) see compared to a regular CSS file? Well, let’s start with the top @... statements; Those are just global variable you can use in the rest of the “Less” file; have a search yourself. One interesting global variable is this one @logo: $logoData;!? This $logoData result magically into a Base64 encoded SVG-image string data:image/svg+xml;base64,PHN2Z...; I don’t have a clue how, but let’s find out. Another interesting answer to find out are the & signs!? And what about the :not(...) function…Is it default CSS? I don’t know. Finally, let’s also find out if other “Less” features have support on our platform? It will be an interesting post!


The $logoData trick

Well, after 2 hours of decompiling-code, checking database entries, and running method-entry remote JVM debug session from the IntelliJ IDE to TomEE, I give up! Looks like the platform is not cooperative with me this time, but it was a wonderful experience again with…

Lessons learned:

  • The database got entries on this query: SELECT * FROM xds_document WHERE "content" LIKE '%data:image/svg+xml;base64,PHN2Z%';
  • These are the Jar-files close in the combat field of my IDE:
    • $CORDYS_HOME/components/cws/cws.jar
    • $CORDYS_HOME/components/cws/lib/cordys.cws.backbone.themeeditor.jar
      • Debug on method entry: ThemeBuildOutputFactory.createCss(); It triggers a remote debug session! Only, $logoData already has a valid value at this moment! Please, comment me if you have a clue…
      • I also saw the abstract class Theme_Base_ passing by where the Base64 string passes by in a constant field!
    • $CORDYS_HOME/components/cws/lib/cordys.cws.buildengine.jar
    • $CORDYS_HOME/components/cws/lib/cwsIde.jar
  • You will see encoded data passing by…You can decode it here
  • I also decompiled the JAR files and tried a search in the content on logoData, but I found nothing!? 😔

…Too bad, but it’s time to continue my life! Let’s see what the future will bring at a better moment in time!

NEXT!


An answer to the &-sign

The &-sign is a real Less-thing called a Parent Selector. This will happen for our Less-part of the platform:

1
2
3
4
5
6
7
8
9
10
11
12
13
body {
&,
&.desktop,
&.mobile,
&.tablet,
.custom-select,
input,
textarea {
font-family: @fontFamily;
color: @fontColor;
}
...
}

Results into…

1
2
3
4
5
6
7
8
9
10
11
body,
body.desktop,
body.mobile,
body.tablet,
body .custom-select,
body input,
body textarea {
font-family: @fontFamily;
color: @fontColor;
}
...

So, it does exactly what it supposes to do…Grab the parent selector and paste it in the correct locations in the CSS…I never viewed it like this before, but indeed reduces the amount off boilerplate CSS code.


The :not(…) function explained

Is it “Less”, or :not(...)!? A quick Google search tells me it is just plain CSS code. It works the same as a generic NOT-logic operator. So, a simple selector like this:

1
2
3
p:not(.different) {
color: red;
}

Will style all <p>-elements; Except the ones that have the class different applied:

1
2
3
4
5
<body>
<p>paragraph1</p>
<p class="different">paragraph2</p>
<p>paragraph3</p>
</body>

This is my resource on that one!

So, now back to our AppWorks example as “what the hell!?” is this Less-CSS-selector selecting from our Less-part: body results-filter bs-drop-button .btn-primary:not(.btn-micro)? Well, have a look at this simple HTML extraction:

1
2
3
4
5
6
7
8
<body>
<results-filter>
<bs-drop-button>
<span class="btn-primary">btnPrimary</span>
<span class="btn-primary btn-micro">btnMicro</span>
</bs-drop-button>
</results-filter>
</body>

What do you think gets a style in this case? Exactly! All <bs-drop-button>-elements within a <results-filter>-elements, and within a <body>-element that have the class btn-primary applied; Except the ones that also have the class btn-micro applied. Have also a look at this JSFiddle example

Great, I at least learned something here…Next one!


Other “Less” functions

For this section of the post, I’m very curious to write logic with if-statements via “Less” functions. For this I enter my ‘Theme’ document again and in the end of the ‘Advanced’ tab (after this last }), I try these Less-parts…

After a publication to runtime, I just validate the custom.css for the outcome (including commented failures!)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
.selected-home-page-name {
color: blue !important;

//Gives an error in the theme editor on save!?
//color: if((2 > 1), blue, green) !important;

//No error, but is also not resolving into correct CSS in runtime!
//color: if(true, blue, green) !important;
}

//This works great...the selector is not visible in the generated CSS!
.selected-home-page-name when (false) {
color: blue !important;
}

//This works too!
.selected-home-page-name when (2 > 1) {
color: blue !important;
}

.selected-home-page-name when (true) {
//Works great...
// The `~` is to remove the double-quotes in the CSS output...
// A typical thing in Less `< v3.5`!
color: replace(~"Red?", "Red\?", blue) !important;
}

@list1: "banana", "tomato", "potato", "peach";
//Works!...watch the NOT!
.selected-home-page-name when not((length(@list1) = 1)) {
color: blue !important;
}

@list2: red, blue, green, gray;
.selected-home-page-name when (true) {
//Check...works!
color: extract(@list2, 2) !important;
}

.selected-home-page-name when (true) {
//Nice try for a `v3.9.0` feature, but not resolving to an expected result!
color: range(4) !important;
}

@selectors: blue, green, red;
//Nope...Not working (`v3.7.0` feature)!! ;)
each(@selectors, {
.selected-home-page-name {
color: @{value} !important;
}
});

.selected-home-page-name {
//Works...
color: rgba(0,0,255,percentage(0.5)) !important;
}

//Working!
.selected-home-page-name when (isurl(url(...))) {
color: blue !important;
}

//Working too!
.selected-home-page-name when (ispercentage(87%)) {
//Works too...
color: color("#aaa") !important;
}

.selected-home-page-name {
@list: red, green 30%, blue;
//`v2.2.0` as it results in non-Base64 code...works!
background-image: svg-gradient(to right, @list);
}

Nice…finally some interesting “Less” examples we can use in our own advantage! 😎

Just a question in between…
What is the version supported for “Less” in our platform? Well, it must be at lease v2.2.0 according to my supported function calls, but we’re definitely not above v3.0.0 because of the failure scenarios!

For a “Less” release overview…Take a look here

During my exploration on all the fancy “Less” functions, I passed by an interesting section with header Properties as Variables. In this section I see a related thing passing by…Smells like my failed $logoData-issue in the beginning of this post!? Would it, or would it not? Let’s do a call like this:

1
2
3
4
5
.selected-home-page-name {
color_var: #efefef;
//A `v3.0.0` feature; NOT resulting a correct outcome in the runtime CSS!
color: $color_var;
}

Too bad…No relation! OpenText really does a magic trick on that $logoData thing; unexplainable from my side now. 😥

!!UPDATE; UPDATE, READ ALL ABOUT!!

I had an inspiration to search the server like this: sudo find /opt -name less -type d. Guess what…a simple result brought me to this file: /opt/opentext/AppWorksPlatform/defaultInst/webroot/shared/thirdparty/less/less.min.js. And guess again…

less_001

Why making things complex when it’s just in front of you! Where did I hear that statement before? 😔 But did we learn something…HELL YEAH! 😜


Great, I leave it with all this “Less” information. It’s always interesting to see how things work and with this little knowledge we now have a better understanding (20%) on how to extend a ‘Theme’ type of document with new “Less” code. Never stop learning new information, but you’re already in the correct place reading this blog post! I see you in the next one on other AppWorks Tips…Cheers.

Don’t forget to subscribe to get updates on the activities happening on this site. Have you noticed the quiz where you find out if you are also “The AppWorks guy”?