-
Notifications
You must be signed in to change notification settings - Fork 2.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Better unit manipulation functions #740
Comments
I'd accept a pull request against master to add these, although there are a number of changes that would have to be done:
|
I'd be glad to give this a shot. If I leave the Beyond that I would just need to know where to look in the current codebase for how to write tests and documentation... |
Tests go in |
I have to say, I'm not a huge fan of these functions. I think they encourage sloppy, inexpressive code and surprising output. I've yet to encounter a use case where the mathematical expression to convert the unit wasn't safer and simple to understand. Please provide use cases for why you think these are necessary. |
For reference, here is how compass lets a user convert a number to have different units: https://github.com/chriseppstein/compass/blob/master/frameworks/compass/stylesheets/compass/typography/_units.scss#L12-L104 We make sure that the numbers are converted correctly according the the defined ratios or details about the conversion's style context. I'm really worried we'll be seeing a lot of code that simply extracts the unit of one number and smashes it into another when a conversion is actually required. |
@chriseppstein I'm certainly sympathetic to those concerns. At the same time, we've been moving in the direction of adding more introspective functions, and right now there really isn't a way to do what these functions are doing. But maybe you're right and there isn't a reason to do what these functions are doing in the first place. I agree that we should see some use cases before we put these in. |
I don't have a use for anything other than the one to remove the unit. // @font-size:
// the size of the current element (eg. `1.5em`)
// @desired-size:
// the desired output size (eg. `1em`)
// @base-size:
// the size of the parent element if you're trying to scale it back to the baseline size (eg. `1.5em` or `.8em`)
// otherwise use the default of `1em` to signify no additional scaling
@function scale-em($font-size, $desired-size, $parent-size: 1em) {
@return if($desired-size == 0, 0, strip-unit($desired-size) / strip-unit($font-size) * $parent-size);
}
.foo {
font-size: 1.5em;
.bar {
font-size: scale-em(1.5em, 1em);
}
} Output: .foo {
font-size: 1.5em;
}
.foo .bar {
font-size: 0.66667em;
} The Compass Most people seem to be avoiding working with ems by using rem with px fallback. If I'm using rem (which I do on occasion to avoid rounding inconsistencies), I want an em fallback. |
My use-case is essentially that I prefer to write complex mixins or functions without having to worry about units. I check the units (or alternately, the ranges) of incoming arguments to know how to handle them; but then I prefer to strip the unit—so I don't have to handle the presence or non-presence of it in internal calculations—and just assert the required output unit on the last line, if one is needed. Stripping the unit, is more common than asserting it but I do use both. One example is with percentage as an input. The input value might be in the range 0-100, with or without a percentage unit, or it might be in the range 0-1. It's easier to do a simple check and then strip the unit for the purpose of internal calculation, and write a function/mixin that can accept united or non-united values without failing. I also use these in typographic sizing, where I have various units and fallback units as well as no-units (line-height) going on. Having the units hanging around just makes things too complicated, it's easier to set them on output. Obviously anybody who uses these functions needs to know what they are doing and needs to test their code. |
Actually As for the return statements you wrote above, it's precisely because of buggy results in using |
@cimmanon the @lunelson writing functions that don't think about units sounds like an anti-pattern.
This sounds very confusing. How do I know whether If the unit math doesn't work out in your functions, that seems a logic smell rather than an indication that Sass needs an easier way to add/remove units. @robwierzbowski SummaryI don't find these use cases very compelling; I'm leaning toward's @chriseppstein's position here, that these functions would encourage more sloppy code than they do add expressive power. |
@nex3, Sorry, you're right. Should be something like |
@lunelson thank you for the patch, but I think the cons outweigh the pros here. |
If any help - when converting units* I use these home cookings (SCSS) // Convert to number
@function number($val){
$u:unit($val);
$u:if($u==px,1px,
if($u==em,1em,
if($u==rem,1rem,
if($u=='%',1%,
if($u==pt,1pt,
if($u==pc,1pc,
if($u==in,1in,
if($u==mm,1mm,
if($u==cm,1cm,
1)))))))));
@return $val/$u;
}
// Example:
.to_number {
px:number(1px);
em:number(1em);
rem:number(1rem);
pct:number(1%);
pt:number(1pt);
pc:number(1pc);
in:number(1in);
mm:number(1mm);
cm:number(1cm);
num:number(1);
}
// Output:
.to_number {
px: 1;
em: 1;
rem: 1;
pct: 1;
pt: 1;
pc: 1;
in: 1;
mm: 1;
cm: 1;
num: 1;
} With the number converter you can now build a base unit converter. I build my functions on a pixel conversion table with a little help from: http://www.translatorscafe.com/cafe/units-converter/typography/calculator/pixel-(X)-to-centimeter-[cm]/ Note! I use html { font-size:100%; } // Unit Conversion Table
// 1px = 0.0625em;
// 1px = 0.0625rem;
// 1px = 0.0625pc;
// 1px = 0.75pt;
// 1px = 0.010416667in;
// 1px = 0.264583333mm;
// 1px = 0.026458333cm;
// Convert to px
@function px($val){
$u:unit($val);
$u:if($u==px,1,
if($u==em,0.0625,
if($u==rem,0.0625,
if($u==pt,0.75,
if($u==pc,0.0625,
if($u==in,0.010416667,
if($u==mm,0.264583333,
if($u==cm,0.026458333,
1))))))));
@return number($val) / $u * 1px;
}
// Example:
.to_px {
px:px(1px);
em:px(1em);
rem:px(1rem);
pt:px(1pt);
pc:px(1pc);
in:px(1in);
mm:px(1mm);
cm:px(1cm);
num:px(1);
}
// Output:
.to_px {
px: 1px;
em: 16px;
rem: 16px;
pt: 1.33333px;
pc: 16px;
in: 96.0px;
mm: 3.77953px;
cm: 37.79528px;
num: 1px;
}
With the base unit converter you can now do the rest - like: @function em($val) { @return if(unitless($val),$val * 1em,number(px($val)) * 0.0625em); }
@function rem($val){ @return if(unitless($val),$val * 1rem,number(px($val)) * 0.0625rem); }
@function pt($val) { @return if(unitless($val),$val * 1pt,number(px($val)) * 0.75pt); }
@function pc($val) { @return if(unitless($val),$val * 1pc,number(px($val)) * 0.0625pc); }
@function in($val) { @return if(unitless($val),$val * 1in,number(px($val)) * 0.010416667in); }
@function mm($val) { @return if(unitless($val),$val * 1mm,number(px($val)) * 0.264583333mm); }
@function cm($val) { @return if(unitless($val),$val * 1cm,number(px($val)) * 0.026458333cm); }
// Example:
.px_to_em_to_cm_to_in_to_back {
px:px(in(cm(em(px(16)))));
}
// Output:
.px_to_em_to_cm_to_in_to_back {
px: 16px;
}
If you want to extend the em converter to handle parents - you could do something like this: @function em($args...){
$val:nth($args,1);
$em:if(unitless($val),$val * 1em,number(px($val)) * 0.0625em);
@for $i from 2 through length($args){$em:$em / number(em(nth($args,$i)))}
@return $em;
}
// Example:
.one_in_half_in_four_in_two {
em:em(1, 0.5em, 4em, em(2));
}
// Output:
.one_in_half_in_four_in_two {
em: 0.25em;
}
Have a wonderful day :) Best, |
@chriseppstein a valid use case for stripping units is in doing math to convert to or from vw/vh units (for example calculating suitable px or em values for fallback in browsers that lack vw/vh support). Since there is no uniform way of handling this conversion it must be done on a case-by-case basis, and requires stripping units. |
I'm encountering some weird bugs with various methods of unit-manipulation that I've tried to do in pure Sass, so I wrote them in SassScript instead.
This is just a starting point; and they lack input error checking but they are pretty handy.
IMHO some version of this should be built in to core Sass... in the meantime I run them as an ad-hoc compass extension
usage examples:
The text was updated successfully, but these errors were encountered: