LESS — data-uri painter mixin

2019-04-14 04:20发布

问题:

I’m trying to implement mixin customizing underline of text, like polyfill for CSS3 text-decoration properties: line, style, color, which are not supported yet by browsers.

My idea is to perform painting proper line in canvas, then convert it to data-uri and use it as background for target element. Problem is when compiling LESS with node.js, there is no canvas in environment. Technically I could use node-canvas to perform this task, but I don’t want to make any dependencies for node just to compile LESS.

Is there a good and simple alternative way to paint micro-image somehow and form data-uri based on this, not engaging external libraries or dependencies?

SOLVED: PNG data-generator code and some demos here. It’s .png mixin that generates indexed-color png, accepts stream of bytes (string) as data, where 00 - transparent color, 01 - passed color.

回答1:

I am not completely sure how exactly you want to implement the mixin (what all you want to do with the mixin), but maybe some of this can help.

  • First: You can use javascript interpolations in javascript implementations of LESS, using back-ticks.

  • Second: There are also some solutions available for drawing micro images in LESS ... I just recently came across this blog post: http://micheljansen.org/blog/entry/1238

And the idea here is to have a simple gif background and just change the color (using some embeded javascript to transform r g b to a 64 bit base). For example to do the wavy line efect like the one used in css text-decoration-style:wavy; you could use the following LESS code:

.wavyrgb(@r,@g,@b) {
    @key: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
    @b64: `function(r,g,b){var key=@{key};return key.charAt(((0&3)<<4)|(r>>4))+key.charAt(((r&15)<<2)|(g>>6))+key.charAt(g&63)+key.charAt(b>>2)+key.charAt(((b&3)<<4)|(255>>4))}(@{r},@{g},@{b})`;
    background-image: ~"url(data:image/gif;base64,R0lGODlhBgADAIAAA@{b64}///yH5BAEAAAEALAAAAAAGAAMAAAIHTAB2lqlQAAA7)";
}

And then place the background image on the bottom for example:

.underwave {
    text-decoration:none;
    .wavyrgb(255,0,0); //red line
    background-repeat:repeat-x;
    background-position:bottom;
}

The output CSS:

.underwave {
  text-decoration: none;
  background-image: url(data:image/gif;base64,R0lGODlhBgADAIAAAP8AAP///yH5BAEAAAEALAAAAAAGAAMAAAIHTAB2lqlQAAA7);
  background-repeat: repeat-x;
  background-position: bottom;
}

The rest now are just some css hints to finalize the approach:

This way with positioning the background-image to top or bottom, you get an overline or underline effect. Which are placed in the back of text using text-decoration-line. If you want to place the line in front of the text, like in the option line-through, you need to use the :afetr pseudoclass in your CSS:

.throughwave {
  text-decoration: none;
  position:relative;
}
.throughwave:after {
  background-image: url(data:image/gif;base64,R0lGODlhBgADAIAAAP8AAP///yH5BAEAAAEALAAAAAAGAAMAAAIHTAB2lqlQAAA7);
  background-repeat: repeat-x;
  background-position: center;
}

There have been also discussions on SO about adding a blinking effect ... for example with CSS animations here:

  • How do you make an image blink?
  • CSS3 animation: blinking overlay box

or you could do the blinking of an element using jQuery.

The combination of effects you can achieve with using multiple background images and position one on top, one on bottom for example.

Here I threw together a quick demo on jsfiddle.


Edit: Pure LESS mixin (no JS):

I wrote a new mixin to calculate the base64 color with LESS only, so it works in all LESS implementations.

This is a LESS 1.4.0 solution:

.b64(@r,@g,@b) {
    @test: "A" "B" "C" "D" "E" "F" "G" "H" "I" "J" "K" "L" "M" "N" "O" "P" "Q" "R" "S" "T" "U" "V" "W" "X" "Y" "Z" "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o" "p" "q" "r" "s" "t" "u" "v" "w" "x" "y" "z" 0 1 2 3 4 5 6 7 8 9 "+" "/" "=";
    @bit1: extract(@test, (floor(@r/16) + 1)); @bit2: extract(@test, (mod(@r,16)*4 + floor(@g/64) + 1)); @bit3: extract(@test, (mod(@g,64) + 1)); @bit4: extract(@test, (floor(@b/4) + 1)); @bit5: extract(@test, (mod(@b,4)*16 + 16));
    b64-color: ~"@{bit1}@{bit2}@{bit3}@{bit4}@{bit5}";
}

This should work in all LESS versions >= 1.1.6:

.b64(@r,@g,@b) {
    @1:"A"; @2:"B"; @3:"C"; @4:"D"; @5:"E"; @6:"F"; @7:"G"; @8:"H"; @9:"I"; @10:"J";    @11:"K";    @12:"L";    @13:"M";    @14:"N";    @15:"O";    @16:"P";    @17:"Q";    @18:"R";    @19:"S";    @20:"T";    @21:"U";    @22:"V";    @23:"W";    @24:"X";    @25:"Y";    @26:"Z";    @27:"a";    @28:"b";    @29:"c";    @30:"d";    @31:"e";    @32:"f";    @33:"g";    @34:"h";    @35:"i";    @36:"j";    @37:"k";    @38:"l";    @39:"m";    @40:"n";    @41:"o";    @42:"p";    @43:"q";    @44:"r";    @45:"s";    @46:"t";    @47:"u";    @48:"v";    @49:"w";    @50:"x";    @51:"y";    @52:"z";    @53:0;  @54:1;  @55:2;  @56:3;  @57:4;  @58:5;  @59:6;  @60:7;  @61:8;  @62:9;  @63:"+";    @64:"/";    @65:"=";
    @modR16: @r - floor(@r/16)*16; @modG64: @g - floor(@g/64)*64; @modB4: @b - floor(@b/4)*4;
    @pos1: (floor(@r/16) + 1); @pos2: (@modR16*4 + floor(@g/64) + 1); @pos3: (@modG64 + 1); @pos4: (floor(@b/4) + 1); @pos5: (@modB4*16 + 16);
    @bit1: @@pos1; @bit2: @@pos2; @bit3: @@pos3; @bit4: @@pos4; @bit5: @@pos5;
    b64-color: ~"@{bit1}@{bit2}@{bit3}@{bit4}@{bit5}";
}


回答2:

The data-uri function is now built-in:

http://lesscss.org/functions/#misc-functions-data-uri