@@ -2574,12 +2574,13 @@ Comparison Functions: ''min()'', ''max()'', and ''clamp()''</h3>
2574
2574
2575
2575
2576
2576
<h3 id=round-func>
2577
- Rounding Values : ''round()''</h3>
2577
+ Stepped Value Functions : ''round()'', ''mod()'', and ''rem ()''</h3>
2578
2578
2579
- The rounding function ''round()''
2580
- adjusts the value of a [=calculation=]
2581
- to a nearby multiple of a given precision [=calculation=] ,
2582
- giving several options for choosing which nearby multiple to use.
2579
+ The stepped-value functions,
2580
+ ''round()'' , ''mod()'' , and ''rem()'' ,
2581
+ all transform a given value
2582
+ according to another "step value",
2583
+ in different ways.
2583
2584
2584
2585
The <dfn lt="round()">round(<<rounding-strategy>>?, A, B)</dfn> function
2585
2586
contains an optional rounding strategy,
@@ -2654,6 +2655,99 @@ Rounding Values: ''round()''</h3>
2654
2655
since block sizes are always non-negative,
2655
2656
''to-zero'' and ''down'' would be identical.)
2656
2657
2658
+ The modulus functions <dfn lt="mod()">mod(A, B)</dfn>
2659
+ and <dfn lt=rem()>rem(A, B)</dfn>
2660
+ similarly contain two [=calculations=] A and B,
2661
+ and return the difference between A
2662
+ and the nearest integer multiple of B either above or below A.
2663
+ The argument [=calculations=] can resolve to any <<number>> , <<dimension>> , or <<percentage>> ,
2664
+ but must have the <em> same</em> [=determine the type of a calculation|type=] ,
2665
+ or else the function is invalid;
2666
+ the result will have the same [=CSSNumericValue/type=] as the arguments.
2667
+
2668
+ The two functions are very similar,
2669
+ and in fact return identical results
2670
+ if both arguments are positive or both are negative:
2671
+ the value of the function is equal to the value of A
2672
+ shifted by the integer multiple of B
2673
+ that brings the value into the range [0, B)
2674
+ (that is, possibly including zero, but excluding B itself).
2675
+
2676
+ <div class=example>
2677
+ For example, ''mod(18px, 5px)'' resolves to the value ''3px'' ,
2678
+ because subtracting ''5px * 3'' from ''18px'' yields ''3px'' ,
2679
+ which is the only such value between ''0px'' and ''3px'' .
2680
+
2681
+ Similarly, ''mod(-140deg, -90deg)'' resolves to the value ''-50deg'' ,
2682
+ because adding ''-90deg * 1'' to ''-140deg'' yields ''-50deg'' ,
2683
+ which is the only such value between ''0deg'' and ''-90deg'' .
2684
+
2685
+ Evaluating either of these examples with ''rem()'' yields the exact same results.
2686
+ </div>
2687
+
2688
+ Their behavior diverges if the A value and the B step
2689
+ are on opposite sides of zero:
2690
+ ''mod()'' (short for “modulus”)
2691
+ continues to choose the integer multiple of B
2692
+ that puts the value into the [0, B) range
2693
+ (guaranteeing that the result will either be zero
2694
+ or share the sign of B, not A),
2695
+ while ''rem()'' (short for "remainder")
2696
+ chooses the integer multiple of B
2697
+ that brings the value into the range [0, -B),
2698
+ avoiding changing the sign of the value.
2699
+
2700
+ <div class=example>
2701
+ For example, ''mod(-18px, 5px)'' resolves to the value ''2px'' :
2702
+ adding ''5px * 4'' to ''-18px'' yields ''2px'' ,
2703
+ which is between ''0px'' and ''5px'' .
2704
+
2705
+ On the other hand, ''rem(-18px, 5px)'' resolves to the value ''-3px'' :
2706
+ adding ''5px * 3'' to ''-18px'' yields ''-3px'' ,
2707
+ which has the same sign as ''-18px''
2708
+ but is between ''0px'' and ''-5px'' .
2709
+
2710
+ Similarly, ''mod(140deg, -90deg)'' resolves to the value ''-40deg''
2711
+ (adding ''-90deg * 2'' to ''140deg'' ,
2712
+ bringing it to between ''0deg'' and ''-90deg'' ),
2713
+ but ''rem(140deg, -90deg)'' resolves to the value ''50deg'' .
2714
+ </div>
2715
+
2716
+ <details>
2717
+ <summary> When should I choose ''mod()'' vs ''rem()'' ?</summary>
2718
+
2719
+ Typically, users of this operation
2720
+ are in control of the step value (B),
2721
+ and are modifying an unknown value A.
2722
+ As a result, it's <em> usually</em> more expected
2723
+ that the result is between 0 and B,
2724
+ regardless of A's sign,
2725
+ meaning ''mod()'' should be chosen.
2726
+
2727
+ For example,
2728
+ if an author wants to know whether a length
2729
+ is an even or odd number of pixels,
2730
+ ''mod(A, 2px)'' will return either ''0px'' or ''1px''
2731
+ (assuming the value is a whole number of pixels to begin with),
2732
+ regardless of the value of a.
2733
+ ''rem(A, 2px)'' , on the other hand,
2734
+ will return ''0px'' if A is an even number of pixels,
2735
+ but will return <em> either</em> ''1px'' or ''-1px''
2736
+ if it's odd,
2737
+ depending on whether A is positive or negative.
2738
+
2739
+ The opposite situation does sometimes occur,
2740
+ however,
2741
+ and so ''rem()'' is provided to cater to that.
2742
+ As well, ''rem()'' is the behavior of JavaScript's <code highlight=js> %</code> operator,
2743
+ so if an exact match between CSS and JS code is desired,
2744
+ ''rem()'' can be useful.
2745
+ </details>
2746
+
2747
+ Note: ''mod()'' and ''rem()''
2748
+ can also be defined directly in terms of other functions:
2749
+ ''mod(A, B)'' is equivalent to ''calc(A - round(down, A, B))'' ,
2750
+ while ''rem(A, B)'' is equivalent to ''calc(A - round(to-zero, A, B))'' .
2657
2751
2658
2752
<h4 id=round-infinities>
2659
2753
Argument Ranges</h4>
@@ -2673,6 +2767,19 @@ Argument Ranges</h4>
2673
2767
if A is 0⁺ or positive finite,
2674
2768
and 0⁻ if A is 0⁻ or negative finite.
2675
2769
2770
+ In ''mod(A, B)'' or ''rem(A, B)'' ,
2771
+ if B is 0,
2772
+ the result is NaN.
2773
+ If A is infinite,
2774
+ the result is NaN.
2775
+
2776
+ In ''mod(A, B)'' only,
2777
+ if B is infinite
2778
+ and A is non-zero and has opposite sign to B,
2779
+ the result is NaN.
2780
+
2781
+ Note: All other "infinite B" cases are valid,
2782
+ and just return A immediately.
2676
2783
2677
2784
2678
2785
<h3 id=trig-funcs>
@@ -3274,6 +3381,8 @@ Syntax</h3>
3274
3381
<<max()>> = max( <<calc-sum>> # )
3275
3382
<<clamp()>> = clamp( <<calc-sum>> #{3} )
3276
3383
<<round()>> = round( <<rounding-strategy>> ?, <<calc-sum>> , <<calc-sum>> )
3384
+ <<mod()>> = mod( <<calc-sum>> , <<calc-sum>> )
3385
+ <<rem()>> = rem( <<calc-sum>> , <<calc-sum>> )
3277
3386
<<sin()>> = sin( <<calc-sum>> )
3278
3387
<<cos()>> = cos( <<calc-sum>> )
3279
3388
<<tan()>> = tan( <<calc-sum>> )
@@ -3413,7 +3522,7 @@ Type Checking</h3>
3413
3522
is «[ "angle" → 1 ] ».
3414
3523
* The [=CSSNumericValue/type=] of a ''pow()'' , ''sqrt()'' , ''log()'' , or ''exp()'' expression
3415
3524
is «[ "number" → 1 ] ».
3416
- * The [=CSSNumericValue/type=] of a ''hypot()'' or ''round ()'' expression
3525
+ * The [=CSSNumericValue/type=] of a ''hypot()'' , ''round()'' , ''mod()'' , or ''rem ()'' expression
3417
3526
is the result of [=add two types|adding the types=]
3418
3527
of its comma-separated [=calculations=] .
3419
3528
0 commit comments