I'm trying to write an SCSS function that returns a URL. (So I could use it like background-image: getURL(thing);)
The difficult thing is I want to interpolate arguments into it, including escaping the args, e.g. # should become %23 so it is URL-safe.
Is this sort of thing even possible with Sass?
#function getURL($name, $color: #ffffff) {
// ???
}
// How I want it to work:
getURL('foo');
// returns: url("http://example.com/foo.png?color=%23ffffff")
// And if possible, this would be cool
// (accepting any color type, and turning it into a hex color):
getURL('bar', rgb(255,0,0));
// returns: url("http://example.com/bar.png?color=%23ff0000")
You could write your own Ruby method to do the URL encoding and color conversion. It looks like Color#inspect returns a hex representation for colors with no alpha value.
You may be able to do some very simple URL encoding with SASS's str- index/insert/slice functions.
It might be easier to fake it:
#function getURL($name, $color-hex-str: ffffff) {
#return url(http://example.com/#{$name}.png?color=%23#{$color-hex-str});
}
Related
I am working on a mixin for breakpoints and I have the following issue.
when a specific state (mode for max-width) is set then the breakpoint should be recalculated by extracting one em value (1px/16 (default font size)).
This is the important part of my code (I might get rid of the function, basically this can be done inline):
$mediaBreakpoint: map-get( $breakpoints, $breakpoint );
// if the mode is for max-width then subtract 1px.
#if map-get( $modes, $mode ) == 'max-width' {
$mediaBreakpoint: calculateMaxWidth(#{$mediaBreakpoint})
}
#debug $mediaBreakpoint;
/**
* calculate the max width based on input
*/
#function calculateMaxWidth($breakpoint){
$newBreakpoint: calc( #{$breakpoint} - 0.0625em ); // 1px in em sizing.
#return $newBreakpoint;
}
But whatever I try, the #debug value shows as:
48em-0.0625em // this is invalid, I need the actual outcome (in this case 47.9375) .
64em // valid min-width
This is the compiled css:
#media screen and (max-width: calc( 48em - 0.0625 )) {
}
What am I missing?
I found the answer myself after a lot of debugging. At first I misunderstood the interpolation. After reading the docs in depth I noticed that I should have wrapped the whole calculation instead of just the variable because I am working inside the map expression.
Quoted from the official Sass docs:
Interpolation can be used almost anywhere in a Sass stylesheet to embed the result of a SassScript expression into a chunk of CSS.
I changed my function to calculate like this and then the mixin started working. hooray!
$newBreakpoint: #{$breakpoint - 0.0625em};
I have two examples that I'm trying to solve:
Example 1
$test: #101E41
body
--colors-dim: rgba(#{$test}, 0.64)
Output: rgba(#101E41, 0.64)
Example 2
body
--colors-active: #101E41
--colors-dim: rgba(var(--colors-active), 0.64)
Output: rgba(var(--colors-active), 0.64)
Both of these look like are examples that should be valid as shown here: https://sass-lang.com/documentation/modules#rgb
Is there something I'm missing?
You need to make use of interpolation to use Sass inside CSS Custom Properties
CSS custom properties, also known as CSS variables, have an unusual declaration syntax: they allow almost any text at all in their declaration values. What’s more, those values are accessible to JavaScript, so any value might potentially be relevant to the user. This includes values that would normally be parsed as SassScript.
Because of this, Sass parses custom property declarations differently than other property declarations. All tokens, including those that look like SassScript, are passed through to CSS as-is. The only exception is interpolation, which is the only way to inject dynamic values into a custom property.
$bar: #900;
:root {
--foo: #{rgba($bar, 0.5)};
}
Results in:
:root {
--foo: rgba(153, 0, 0, 0.5);
}
For your second example, you're going to have to get a little... creative... since Sass will bail and ignore any CSS Custom Property syntax it sees, you can't make use of Sass's rgba function with Custom Properties - the Sass compiler won't resolve the values for you.
Thankfully, you can still use the native CSS rgba function with Custom Properties, the only downside is that you'll need to break your hexadecimal value into its R, G, and B values.
#function toRGB($color)
#return red($color), green($color), blue($color)
$bar: #900
:root
--foo: #{$bar}
--foo-rgb: #{toRGB($bar)}
--foo-dim: #{rgba($bar, 0.5)}
--foo-dim: rgba(var(--foo-rgb), 0.5)
.button
background-color: var(--foo-dim)
Compiles to:
:root {
--foo: #900;
--foo-rgb: 153, 0, 0;
--foo-dim: rgba(153, 0, 0, 0.5);
--foo-dim: rgba(var(--foo-rgb), 0.5);
}
.button {
background-color: var(--foo-dim);
}
https://www.sassmeister.com/gist/39ffc57c492de73066831afe5a9696f6
The Question:
Is there a SASS function/technique that transforms a HEX value to a simple RGB string.
Simple here meaning just a string without it being enclosed in rgb() ?
E.g: #D50000 --> "213,0,0"
Why I need this:
I'm using Material Design Lite as my UI 'framework'. More specifically I'm using the SASS version so I can tweak the color variables according to my app's style-guide.
For some reason the color variables in _variables.scss of MDL take this format for color definitions:
$color-primary: "0,0,0" !default; // supposed to be black
which is really, really odd. I expected, at most, something along the lines of
$color-primary: rgba(0,0,0,1) !default;
My color variables are stored in another file called _globals.scss in which I store my variables in regular HEX format so I can easily reuse them in other places:
$brand-primary: #FA3166;
$brand-primary-dark: #E02C59;
I don't want to define 2 times my colours (1 HEX & 1 MDL-compatible RGB string), hence the reason I need to transform HEX to RGB-string.
#nicholas-kyriakides's answer works perfectly fine, but here is a more concise function using Sass interpolation.
#function hexToRGBString($hexColor) {
#return "#{red($hexColor)},#{green($hexColor)},#{blue($hexColor)}";
}
You can pass in either a hex either explicity or from rgb() or rgba() with opacity as 1.
For example:
$color-white: hexToRGBString(#fff) => "255,255,255"
$color-white: hexToRGBString(rgb(255,255,255)) => "255,255,255"
$color-white: hexToRGBString(rgba(#fff,1)) => "255,255,255"
I've hacked around it with a SASS function:
#function hexToString($hexColor) {
// 0.999999 val in alpha actually compiles to 1.0
$rgbaVal: inspect(rgba($hexColor,0.9999999));
// slice substring between 'rgba(' and '1.0)'
#return str-slice($rgbaVal, 6, str-length($rgbaVal)-6);
}
Usage:
$brand-primary: #333;
$color-primary: hexToString($brand-primary);
I think the MDL team intended to have a different way to customise the palette and I'm missing it, so if someone knows a better way to customise MDL's palette I'm open to suggestions. Either way this solves the original question.
I am writing a #mixin with some math in it that calculates the percentage width of an element, but since it is very useful I would like to use the same function for other properties too, like margins and paddings.
Is there a way to pass the property name as an argument to a mixin?
#mixin w_fluid($property_name, $w_element,$w_parent:16) {
$property_name: percentage(($w_element/$w_parent));
}
You need to use interpolation (eg. #{$var}) on your variable in order for Sass to treat it as a CSS property. Without it, you're just performing variable assignment.
#mixin w_fluid($property_name, $w_element, $w_parent:16) {
#{$property_name}: percentage(($w_element / $w_parent));
}
In addition to the #rcorbellini response
You can use string and variable together
#mixin margin($direction) { // element spacing
margin-#{$direction}: 10px;
}
I'm trying to check in Selenium if an element has a green border or not.
i can use //div[#id="target"]/#style to get the parsed style string applied... and use string search to search for the border... i have to work around some brosers showing the shorthand (border: solid 3px green) and other showing the expanded (border-style: solid; border-color: green....) ...but how could i do that more cleanly?
ideally something like: //div[#id="target"]/#style.borderColor
I also would like to avoid using the contains selector because the syntax is awful. But if it's the only way, so be it. of course.
XPath doesn't know anything about CSS styles, it doesn't understand the attributes and takes them just as simple strings. It would be weird if a XML query language understood CSS styles, right?
Besides, the getAttribute() uses a construct similar to XPath, but not XPath! It also selects the attribute via # sign, right. But consider this locator: "id=target#style". It would work, but it's definitely no XPath.
It would also return the explicitly set style attribute, not it's internal computed value, so it's useless unless there actually is a style attribute on the element. If there is style attribute defined, go for it.
Selenium itself can't give you the right answer (WebDriver has getCssValue(), but there's no counterpart for it in Selenium RC, afaik).
Therefore, the only way to get the computed style (the final value computed from all sources) of an element in Selenium RC is via JavaScript.
The script that has been working for me for ages (after a slight edit) is this (from quirksmode.org):
function getStyle(id, stylePropJs, stylePropCss) {
var x = document.getElementById(id);
if (x.currentStyle)
var y = x.currentStyle[stylePropJs];
else if (window.getComputedStyle)
var y = document.defaultView.getComputedStyle(x,null).getPropertyValue(stylePropCss);
return y;
}
Note that IE needs a JavaScript name of the property, but every other browser uses CSS names. Also, you can't use the shorthand property and you definitely must use the expanded one. Therefore, in your case:
String script = "var x = document.getElementById('target');" +
"if (x.currentStyle) var y = x.currentStyle['borderTopColor'];" +
"else if (window.getComputedStyle) var y = document.defaultView.getComputedStyle(x,null).getPropertyValue('border-top-color');" +
"y;";
String color = selenium.getEval(script);
This returns the color of the top border (yep, you'll need to call it four times in order to get the whole border) of the target element. But guess what! Every browser returns the color in a different format. Fortunately, at least in Java, there's a Color class that can easily reformat it:
String color = Color.fromString(color).asHex();
Now that you have a hex encoded color stored, you can trivially make check whether it's green or not.