123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398 |
- /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
- /*
- * This Source Code is subject to the terms of the Mozilla Public License
- * version 2.0 (the "License"). You can obtain a copy of the License at
- * http://mozilla.org/MPL/2.0/.
- */
- /**
- * For the purposes of this test, flex items are specified as a hash with a
- * hash-entry for each CSS property that is to be set. In these per-property
- * entries, the key is the property-name, and the value can be either of the
- * following:
- * (a) the property's specified value (which indicates that we don't need to
- * bother checking the computed value of this particular property)
- * ...OR...
- * (b) an array with 2-3 entries...
- * [specifiedValue, expectedComputedValue (, epsilon) ]
- * ...which indicates that the property's computed value should be
- * checked. The array's first entry (for the specified value) may be
- * null; this means that no value should be explicitly specified for this
- * property. The second entry is the property's expected computed
- * value. The third (optional) entry is an epsilon value, which allows for
- * fuzzy equality when testing the computed value.
- *
- * To allow these testcases to be re-used in both horizontal and vertical
- * flex containers, we specify "width"/"min-width"/etc. using the aliases
- * "_main-size", "_min-main-size", etc. The test code can map these
- * placeholder names to their corresponding property-names using the maps
- * defined below -- gRowPropertyMapping, gColumnPropertyMapping, etc.
- *
- * If the testcase needs to customize its flex container at all (e.g. by
- * specifying a custom container-size), it can do so by including a hash
- * called "container_properties", with propertyName:propertyValue mappings.
- * (This hash can use aliased property-names like "_main-size" as well.)
- */
- // The standard main-size we'll use for our flex container when setting up
- // the testcases defined below:
- var gDefaultFlexContainerSize = "200px";
- // Left-to-right versions of placeholder property-names used in
- // testcases below:
- var gRowPropertyMapping =
- {
- "_main-size": "width",
- "_min-main-size": "min-width",
- "_max-main-size": "max-width",
- "_border-main-start-width": "border-left-width",
- "_border-main-end-width": "border-right-width",
- "_padding-main-start": "padding-left",
- "_padding-main-end": "padding-right",
- "_margin-main-start": "margin-left",
- "_margin-main-end": "margin-right"
- };
- // Right-to-left versions of placeholder property-names used in
- // testcases below:
- var gRowReversePropertyMapping =
- {
- "_main-size": "width",
- "_min-main-size": "min-width",
- "_max-main-size": "max-width",
- "_border-main-start-width": "border-right-width",
- "_border-main-end-width": "border-left-width",
- "_padding-main-start": "padding-right",
- "_padding-main-end": "padding-left",
- "_margin-main-start": "margin-right",
- "_margin-main-end": "margin-left"
- };
- // Top-to-bottom versions of placeholder property-names used in
- // testcases below:
- var gColumnPropertyMapping =
- {
- "_main-size": "height",
- "_min-main-size": "min-height",
- "_max-main-size": "max-height",
- "_border-main-start-width": "border-top-width",
- "_border-main-end-width": "border-bottom-width",
- "_padding-main-start": "padding-top",
- "_padding-main-end": "padding-bottom",
- "_margin-main-start": "margin-top",
- "_margin-main-end": "margin-bottom"
- };
- // Bottom-to-top versions of placeholder property-names used in
- // testcases below:
- var gColumnReversePropertyMapping =
- {
- "_main-size": "height",
- "_min-main-size": "min-height",
- "_max-main-size": "max-height",
- "_border-main-start-width": "border-bottom-width",
- "_border-main-end-width": "border-top-width",
- "_padding-main-start": "padding-bottom",
- "_padding-main-end": "padding-top",
- "_margin-main-start": "margin-bottom",
- "_margin-main-end": "margin-top"
- };
- // The list of actual testcase definitions:
- var gFlexboxTestcases =
- [
- // No flex properties specified --> should just use 'width' for sizing
- {
- items:
- [
- { "_main-size": [ "40px", "40px" ] },
- { "_main-size": [ "65px", "65px" ] },
- ]
- },
- // flex-basis is specified:
- {
- items:
- [
- { "flex-basis": "50px",
- "_main-size": [ null, "50px" ]
- },
- {
- "flex-basis": "20px",
- "_main-size": [ null, "20px" ]
- },
- ]
- },
- // flex-basis is *large* -- sum of flex-basis values is > flex container size:
- // (w/ 0 flex-shrink so we don't shrink):
- {
- items:
- [
- {
- "flex": "0 0 150px",
- "_main-size": [ null, "150px" ]
- },
- {
- "flex": "0 0 90px",
- "_main-size": [ null, "90px" ]
- },
- ]
- },
- // flex-basis is *large* -- each flex-basis value is > flex container size:
- // (w/ 0 flex-shrink so we don't shrink):
- {
- items:
- [
- {
- "flex": "0 0 250px",
- "_main-size": [ null, "250px" ]
- },
- {
- "flex": "0 0 400px",
- "_main-size": [ null, "400px" ]
- },
- ]
- },
- // flex-basis has percentage value:
- {
- items:
- [
- {
- "flex-basis": "30%",
- "_main-size": [ null, "60px" ]
- },
- {
- "flex-basis": "45%",
- "_main-size": [ null, "90px" ]
- },
- ]
- },
- // flex-basis has calc(percentage) value:
- {
- items:
- [
- {
- "flex-basis": "calc(20%)",
- "_main-size": [ null, "40px" ]
- },
- {
- "flex-basis": "calc(80%)",
- "_main-size": [ null, "160px" ]
- },
- ]
- },
- // flex-basis has calc(percentage +/- length) value:
- {
- items:
- [
- {
- "flex-basis": "calc(10px + 20%)",
- "_main-size": [ null, "50px" ]
- },
- {
- "flex-basis": "calc(60% - 1px)",
- "_main-size": [ null, "119px" ]
- },
- ]
- },
- // flex-grow is specified:
- {
- items:
- [
- {
- "flex": "1",
- "_main-size": [ null, "60px" ]
- },
- {
- "flex": "2",
- "_main-size": [ null, "120px" ]
- },
- {
- "flex": "0 20px",
- "_main-size": [ null, "20px" ]
- }
- ]
- },
- // Same ratio as prev. testcase; making sure we handle float inaccuracy
- {
- items:
- [
- {
- "flex": "100000",
- "_main-size": [ null, "60px" ]
- },
- {
- "flex": "200000",
- "_main-size": [ null, "120px" ]
- },
- {
- "flex": "0.000001 20px",
- "_main-size": [ null, "20px" ]
- }
- ]
- },
- // Same ratio as prev. testcase, but with items cycled and w/
- // "flex: none" & explicit size instead of "flex: 0 20px"
- {
- items:
- [
- {
- "flex": "none",
- "_main-size": [ "20px", "20px" ]
- },
- {
- "flex": "1",
- "_main-size": [ null, "60px" ]
- },
- {
- "flex": "2",
- "_main-size": [ null, "120px" ]
- }
- ]
- },
- // ...and now with flex-grow:[huge] to be sure we handle infinite float values
- // gracefully.
- {
- items:
- [
- {
- "flex": "9999999999999999999999999999999999999999999999999999999",
- "_main-size": [ null, "200px" ]
- },
- ]
- },
- {
- items:
- [
- {
- "flex": "9999999999999999999999999999999999999999999999999999999",
- "_main-size": [ null, "50px" ]
- },
- {
- "flex": "9999999999999999999999999999999999999999999999999999999",
- "_main-size": [ null, "50px" ]
- },
- {
- "flex": "9999999999999999999999999999999999999999999999999999999",
- "_main-size": [ null, "50px" ]
- },
- {
- "flex": "9999999999999999999999999999999999999999999999999999999",
- "_main-size": [ null, "50px" ]
- },
- ]
- },
- {
- items:
- [
- {
- "flex": "99999999999999999999999999999999999",
- "_main-size": [ null, "50px" ]
- },
- {
- "flex": "99999999999999999999999999999999999",
- "_main-size": [ null, "50px" ]
- },
- {
- "flex": "99999999999999999999999999999999999",
- "_main-size": [ null, "50px" ]
- },
- {
- "flex": "99999999999999999999999999999999999",
- "_main-size": [ null, "50px" ]
- },
- ]
- },
- // And now, some testcases to check that we handle float accumulation error
- // gracefully.
- // First, a testcase with just a custom-sized huge container, to be sure we'll
- // be able to handle content on that scale, in the subsequent more-complex
- // testcases:
- {
- container_properties:
- {
- "_main-size": "9000000px"
- },
- items:
- [
- {
- "flex": "1",
- "_main-size": [ null, "9000000px" ]
- },
- ]
- },
- // ...and now with two flex items dividing up that container's huge size:
- {
- container_properties:
- {
- "_main-size": "9000000px"
- },
- items:
- [
- {
- "flex": "2",
- "_main-size": [ null, "6000000px" ]
- },
- {
- "flex": "1",
- "_main-size": [ null, "3000000px" ]
- },
- ]
- },
- // OK, now to actually test accumulation error. Below, we have six flex items
- // splitting up the container's size, with huge differences between flex
- // weights. For simplicity, I've set up the weights so that they sum exactly
- // to the container's size in px. So 1 unit of flex *should* get you 1px.
- //
- // NOTE: The expected computed "_main-size" values for the flex items below
- // appear to add up to more than their container's size, which would suggest
- // that they overflow their container unnecessarily. But they don't actually
- // overflow -- this discrepancy is simply because Gecko's code for reporting
- // computed-sizes rounds to 6 significant figures (in particular, the method
- // (nsTSubstring_CharT::AppendFloat() does this). Internally, in app-units,
- // the child frames' main-sizes add up exactly to the container's main-size,
- // as you'd hope & expect.
- {
- container_properties:
- {
- "_main-size": "9000000px"
- },
- items:
- [
- {
- "flex": "3000000",
- "_main-size": [ null, "3000000px" ]
- },
- {
- "flex": "1",
- "_main-size": [ null, "1px" ]
- },
- {
- "flex": "1",
- "_main-size": [ null, "1px" ]
- },
- {
- "flex": "2999999",
- // NOTE: Expected value is off slightly, from float error when
- // resolving flexible lengths & when generating computed value string:
- "_main-size": [ null, "3000000px" ]
- },
- {
- "flex": "2999998",
- // NOTE: Expected value is off slightly, from float error when
- // resolving flexible lengths & when generating computed value string:
- "_main-size": [ null, "3000000px" ]
- },
- {
- "flex": "1",
- "_main-size": [ null, "1px", 0.2 ]
- },
- ]
- },
- // Same flex items as previous testcase, but now reordered such that the items
- // with tiny flex weights are all listed last:
- {
- container_properties:
- {
- "_main-size": "9000000px"
- },
- items:
- [
- {
- "flex": "3000000",
- "_main-size": [ null, "3000000px" ]
- },
- {
- "flex": "2999999",
- // NOTE: Expected value is off slightly, from float error when
- // resolving flexible lengths & when generating computed value string:
- "_main-size": [ null, "3000000px" ]
- },
- {
- "flex": "2999998",
- // NOTE: Expected value is off slightly, from float error when
- // resolving flexible lengths & when generating computed value string:
- "_main-size": [ null, "3000000px" ]
- },
- {
- "flex": "1",
- "_main-size": [ null, "1px", 0.2 ]
- },
- {
- "flex": "1",
- "_main-size": [ null, "1px", 0.2 ]
- },
- {
- "flex": "1",
- "_main-size": [ null, "1px", 0.2 ]
- },
- ]
- },
- // Same flex items as previous testcase, but now reordered such that the items
- // with tiny flex weights are all listed first:
- {
- container_properties:
- {
- "_main-size": "9000000px"
- },
- items:
- [
- {
- "flex": "1",
- // NOTE: Expected value is off slightly, from float error when
- // resolving flexible lengths:
- "_main-size": [ null, "1px", 0.2 ]
- },
- {
- "flex": "1",
- // NOTE: Expected value is off slightly, from float error when
- // resolving flexible lengths:
- "_main-size": [ null, "1px", 0.2 ]
- },
- {
- "flex": "1",
- // NOTE: Expected value is off slightly, from float error when
- // resolving flexible lengths:
- "_main-size": [ null, "1px", 0.2 ]
- },
- {
- "flex": "3000000",
- "_main-size": [ null, "3000000px" ]
- },
- {
- "flex": "2999999",
- // NOTE: Expected value is off slightly, from float error when
- // resolving flexible lengths & when generating computed value string:
- "_main-size": [ null, "3000000px" ]
- },
- {
- "flex": "2999998",
- // NOTE: Expected value is off slightly, from float error when
- // resolving flexible lengths & when generating computed value string:
- "_main-size": [ null, "3000000px" ]
- },
- ]
- },
- // Trying "flex: auto" (== "1 1 auto") w/ a mix of flex-grow/flex-basis values
- {
- items:
- [
- {
- "flex": "auto",
- "_main-size": [ null, "45px" ]
- },
- {
- "flex": "2",
- "_main-size": [ null, "90px" ]
- },
- {
- "flex": "20px 1 0",
- "_main-size": [ null, "65px" ]
- }
- ]
- },
- // Same as previous, but with items cycled & different syntax
- {
- items:
- [
- {
- "flex": "20px",
- "_main-size": [ null, "65px" ]
- },
- {
- "flex": "1",
- "_main-size": [ null, "45px" ]
- },
- {
- "flex": "2",
- "_main-size": [ null, "90px" ]
- }
- ]
- },
- {
- items:
- [
- {
- "flex": "2",
- "_main-size": [ null, "100px" ],
- "border": "0px dashed",
- "_border-main-start-width": [ "5px", "5px" ],
- "_border-main-end-width": [ "15px", "15px" ],
- "_margin-main-start": [ "22px", "22px" ],
- "_margin-main-end": [ "8px", "8px" ]
- },
- {
- "flex": "1",
- "_main-size": [ null, "50px" ],
- "_margin-main-start": [ "auto", "0px" ],
- "_padding-main-end": [ "auto", "0px" ],
- }
- ]
- },
- // Test negative flexibility:
- // Basic testcase: just 1 item (relying on initial "flex-shrink: 1") --
- // should shrink to container size.
- {
- items:
- [
- { "_main-size": [ "400px", "200px" ] },
- ],
- },
- // ...and now with a "flex" specification and a different flex-shrink value:
- {
- items:
- [
- {
- "flex": "4 2 250px",
- "_main-size": [ null, "200px" ]
- },
- ],
- },
- // ...and now with multiple items, which all shrink proportionally (by 50%)
- // to fit to the container, since they have the same (initial) flex-shrink val
- {
- items:
- [
- { "_main-size": [ "80px", "40px" ] },
- { "_main-size": [ "40px", "20px" ] },
- { "_main-size": [ "30px", "15px" ] },
- { "_main-size": [ "250px", "125px" ] },
- ]
- },
- // ...and now with positive flexibility specified. (should have no effect, so
- // everything still shrinks by the same proportion, since the flex-shrink
- // values are all the same).
- {
- items:
- [
- {
- "flex": "4 3 100px",
- "_main-size": [ null, "80px" ]
- },
- {
- "flex": "5 3 50px",
- "_main-size": [ null, "40px" ]
- },
- {
- "flex": "0 3 100px",
- "_main-size": [ null, "80px" ]
- }
- ]
- },
- // ...and now with *different* flex-shrink values:
- {
- items:
- [
- {
- "flex": "4 2 50px",
- "_main-size": [ null, "30px" ]
- },
- {
- "flex": "5 3 50px",
- "_main-size": [ null, "20px" ]
- },
- {
- "flex": "0 0 150px",
- "_main-size": [ null, "150px" ]
- }
- ]
- },
- // Same ratio as prev. testcase; making sure we handle float inaccuracy
- {
- items:
- [
- {
- "flex": "4 20000000 50px",
- "_main-size": [ null, "30px" ]
- },
- {
- "flex": "5 30000000 50px",
- "_main-size": [ null, "20px" ]
- },
- {
- "flex": "0 0.0000001 150px",
- "_main-size": [ null, "150px" ]
- }
- ]
- },
- // Another "different flex-shrink values" testcase:
- {
- items:
- [
- {
- "flex": "4 2 115px",
- "_main-size": [ null, "69px" ]
- },
- {
- "flex": "5 1 150px",
- "_main-size": [ null, "120px" ]
- },
- {
- "flex": "1 4 30px",
- "_main-size": [ null, "6px" ]
- },
- {
- "flex": "1 0 5px",
- "_main-size": [ null, "5px" ]
- },
- ]
- },
- // ...and now with min-size (clamping the effects of flex-shrink on one item):
- {
- items:
- [
- {
- "flex": "4 5 75px",
- "_min-main-size": "50px",
- "_main-size": [ null, "50px" ],
- },
- {
- "flex": "5 5 100px",
- "_main-size": [ null, "62.5px" ]
- },
- {
- "flex": "0 4 125px",
- "_main-size": [ null, "87.5px" ]
- }
- ]
- },
- // Test a min-size that's much larger than initial preferred size, but small
- // enough that our flexed size pushes us over it:
- {
- items:
- [
- {
- "flex": "auto",
- "_min-main-size": "110px",
- "_main-size": [ "50px", "125px" ]
- },
- {
- "flex": "auto",
- "_main-size": [ null, "75px" ]
- }
- ]
- },
- // Test a min-size that's much larger than initial preferred size, and is
- // even larger than our positively-flexed size, so that we have to increase it
- // (as a 'min violation') after we've flexed.
- {
- items:
- [
- {
- "flex": "auto",
- "_min-main-size": "150px",
- "_main-size": [ "50px", "150px" ]
- },
- {
- "flex": "auto",
- "_main-size": [ null, "50px" ]
- }
- ]
- },
- // Test min-size on multiple items simultaneously:
- {
- items:
- [
- {
- "flex": "auto",
- "_min-main-size": "20px",
- "_main-size": [ null, "20px" ]
- },
- {
- "flex": "9 auto",
- "_min-main-size": "150px",
- "_main-size": [ "50px", "180px" ]
- },
- ]
- },
- {
- items:
- [
- {
- "flex": "1 1 0px",
- "_min-main-size": "90px",
- "_main-size": [ null, "90px" ]
- },
- {
- "flex": "1 1 0px",
- "_min-main-size": "80px",
- "_main-size": [ null, "80px" ]
- },
- {
- "flex": "1 1 40px",
- "_main-size": [ null, "30px" ]
- }
- ]
- },
- // Test a case where _min-main-size will be violated on different items in
- // successive iterations of the "resolve the flexible lengths" loop
- {
- items:
- [
- {
- "flex": "1 2 100px",
- "_min-main-size": "90px",
- "_main-size": [ null, "90px" ]
- },
- {
- "flex": "1 1 100px",
- "_min-main-size": "70px",
- "_main-size": [ null, "70px" ]
- },
- {
- "flex": "1 1 100px",
- "_main-size": [ null, "40px" ]
- }
- ]
- },
- // Test some cases that have a min-size violation on one item and a
- // max-size violation on another:
- // Here, both items initially grow to 100px. That violates both
- // items' sizing constraints (it's smaller than the min-size and larger than
- // the max-size), so we clamp both of them and sum the clamping-differences:
- //
- // (130px - 100px) + (50px - 100px) = (30px) + (-50px) = -20px
- //
- // This sum is negative, so (per spec) we freeze the item that had its
- // max-size violated (the second one) and restart the algorithm. This time,
- // all the available space (200px - 50px = 150px) goes to the not-yet-frozen
- // first item, and that puts it above its min-size, so all is well.
- {
- items:
- [
- {
- "flex": "auto",
- "_min-main-size": "130px",
- "_main-size": [ null, "150px" ]
- },
- {
- "flex": "auto",
- "_max-main-size": "50px",
- "_main-size": [ null, "50px" ]
- },
- ]
- },
- // As above, both items initially grow to 100px, and that violates both items'
- // constraints. However, now the sum of the clamping differences is:
- //
- // (130px - 100px) + (80px - 100px) = (30px) + (-20px) = 10px
- //
- // This sum is positive, so (per spec) we freeze the item that had its
- // min-size violated (the first one) and restart the algorithm. This time,
- // all the available space (200px - 130px = 70px) goes to the not-yet-frozen
- // second item, and that puts it below its max-size, so all is well.
- {
- items:
- [
- {
- "flex": "auto",
- "_min-main-size": "130px",
- "_main-size": [ null, "130px" ]
- },
- {
- "flex": "auto",
- "_max-main-size": "80px",
- "_main-size": [ null, "70px" ]
- },
- ]
- },
- // As above, both items initially grow to 100px, and that violates both items'
- // constraints. So we clamp both items and sum the clamping differences to
- // see what to do next. The sum is:
- //
- // (80px - 100px) + (120px - 100px) = (-20px) + (20px) = 0px
- //
- // Per spec, if the sum is 0, we're done -- we leave both items at their
- // clamped sizes.
- {
- items:
- [
- {
- "flex": "auto",
- "_max-main-size": "80px",
- "_main-size": [ null, "80px" ]
- },
- {
- "flex": "auto",
- "_min-main-size": "120px",
- "_main-size": [ null, "120px" ]
- },
- ]
- },
- // Test cases where flex-grow sums to less than 1:
- // ===============================================
- // This makes us treat the flexibilities like "fraction of free space"
- // instead of weights, so that e.g. a single item with "flex-grow: 0.1"
- // will only get 10% of the free space instead of all of the free space.
- // Basic cases where flex-grow sum is less than 1:
- {
- items:
- [
- {
- "flex": "0.1 100px",
- "_main-size": [ null, "110px" ] // +10% of free space
- },
- ]
- },
- {
- items:
- [
- {
- "flex": "0.8 0px",
- "_main-size": [ null, "160px" ] // +80% of free space
- },
- ]
- },
- // ... and now with two flex items:
- {
- items:
- [
- {
- "flex": "0.4 70px",
- "_main-size": [ null, "110px" ] // +40% of free space
- },
- {
- "flex": "0.2 30px",
- "_main-size": [ null, "50px" ] // +20% of free space
- },
- ]
- },
- // ...and now with max-size modifying how much free space one item can take:
- {
- items:
- [
- {
- "flex": "0.4 70px",
- "_main-size": [ null, "110px" ] // +40% of free space
- },
- {
- "flex": "0.2 30px",
- "_max-main-size": "35px",
- "_main-size": [ null, "35px" ] // +20% free space, then clamped
- },
- ]
- },
- // ...and now with a max-size smaller than our flex-basis:
- // (This makes us freeze the second item right away, before we compute
- // the initial free space.)
- {
- items:
- [
- {
- "flex": "0.4 70px",
- "_main-size": [ null, "118px" ] // +40% of 200px-70px-10px
- },
- {
- "flex": "0.2 30px",
- "_max-main-size": "10px",
- "_main-size": [ null, "10px" ] // immediately frozen
- },
- ]
- },
- // ...and now with a max-size and a huge flex-basis, such that we initially
- // have negative free space, which makes the "% of [original] free space"
- // calculations a bit more subtle. We set the "original free space" after
- // we've clamped the second item (the first time the free space is positive).
- {
- items:
- [
- {
- "flex": "0.4 70px",
- "_main-size": [ null, "118px" ] // +40% of free space _after freezing
- // the other item_
- },
- {
- "flex": "0.2 150px",
- "_max-main-size": "10px",
- "_main-size": [ null, "10px" ] // clamped immediately
- },
- ]
- },
- // Now with min-size modifying how much free space our items take:
- {
- items:
- [
- {
- "flex": "0.4 70px",
- "_main-size": [ null, "110px" ] // +40% of free space
- },
- {
- "flex": "0.2 30px",
- "_min-main-size": "70px",
- "_main-size": [ null, "70px" ] // +20% free space, then clamped
- },
- ]
- },
- // ...and now with a large enough min-size that it prevents the other flex
- // item from taking its full desired portion of the original free space:
- {
- items:
- [
- {
- "flex": "0.4 70px",
- "_main-size": [ null, "80px" ] // (Can't take my full +40% of
- // free space due to other item's
- // large min-size.)
- },
- {
- "flex": "0.2 30px",
- "_min-main-size": "120px",
- "_main-size": [ null, "120px" ] // +20% free space, then clamped
- },
- ]
- },
- // ...and now with a large-enough min-size that it pushes the other flex item
- // to actually shrink a bit (with default "flex-shrink:1"):
- {
- items:
- [
- {
- "flex": "0.3 30px",
- "_main-size": [ null, "20px" ] // -10px, instead of desired +45px
- },
- {
- "flex": "0.2 20px",
- "_min-main-size": "180px",
- "_main-size": [ null, "180px" ] // +160px, instead of desired +30px
- },
- ]
- },
- // In this case, the items' flexibilities don't initially sum to < 1, but they
- // do after we freeze the third item for violating its max-size.
- {
- items:
- [
- {
- "flex": "0.3 30px",
- "_main-size": [ null, "75px" ]
- // 1st loop: desires (0.3 / 5) * 150px = 9px. Tentatively granted.
- // 2nd loop: desires 0.3 * 150px = 45px. Tentatively granted.
- // 3rd loop: desires 0.3 * 150px = 45px. Granted +45px.
- },
- {
- "flex": "0.2 20px",
- "_max-main-size": "30px",
- "_main-size": [ null, "30px" ]
- // First loop: desires (0.2 / 5) * 150px = 6px. Tentatively granted.
- // Second loop: desires 0.2 * 150px = 30px. Frozen at +10px.
- },
- {
- "flex": "4.5 0px",
- "_max-main-size": "20px",
- "_main-size": [ null, "20px" ]
- // First loop: desires (4.5 / 5) * 150px = 135px. Frozen at +20px.
- },
- ]
- },
- // Make sure we calculate "original free space" correctly when one of our
- // flex items will be clamped right away, due to max-size preventing it from
- // growing at all:
- {
- // Here, the second flex item is effectively inflexible; it's
- // immediately frozen at 40px since we're growing & this item's max size
- // trivially prevents it from growing. This leaves us with an "original
- // free space" of 60px. The first flex item takes half of that, due to
- // its flex-grow value of 0.5.
- items:
- [
- {
- "flex": "0.5 100px",
- "_main-size": [ null, "130px" ]
- },
- {
- "flex": "1 98px",
- "_max-main-size": "40px",
- "_main-size": [ null, "40px" ]
- },
- ]
- },
- {
- // Same as previous example, but with a larger flex-basis on the second
- // element (which shouldn't ultimately matter, because its max size clamps
- // its size immediately anyway).
- items:
- [
- {
- "flex": "0.5 100px",
- "_main-size": [ null, "130px" ]
- },
- {
- "flex": "1 101px",
- "_max-main-size": "40px",
- "_main-size": [ null, "40px" ]
- },
- ]
- },
- {
- // Here, the third flex item is effectively inflexible; it's immediately
- // frozen at 0px since we're growing & this item's max size trivially
- // prevents it from growing. This leaves us with an "original free space" of
- // 100px. The first flex item takes 40px, and the third takes 50px, due to
- // their flex values of 0.4 and 0.5.
- items:
- [
- {
- "flex": "0.4 50px",
- "_main-size": [ null, "90px" ]
- },
- {
- "flex": "0.5 50px",
- "_main-size": [ null, "100px" ]
- },
- {
- "flex": "0 90px",
- "_max-main-size": "0px",
- "_main-size": [ null, "0px" ]
- },
- ]
- },
- {
- // Same as previous example, but with slightly larger flex-grow values on
- // the first and second items, which sum to 1.0 and produce slightly larger
- // main sizes. This demonstrates that there's no discontinuity between the
- // "< 1.0 sum" to ">= 1.0 sum" behavior, in this situation at least.
- items:
- [
- {
- "flex": "0.45 50px",
- "_main-size": [ null, "95px" ]
- },
- {
- "flex": "0.55 50px",
- "_main-size": [ null, "105px" ]
- },
- {
- "flex": "0 90px",
- "_max-main-size": "0px",
- "_main-size": [ null, "0px" ]
- },
- ]
- },
- // Test cases where flex-shrink sums to less than 1:
- // =================================================
- // This makes us treat the flexibilities more like "fraction of (negative)
- // free space" instead of weights, so that e.g. a single item with
- // "flex-shrink: 0.1" will only shrink by 10% of amount that it overflows
- // its container by.
- //
- // It gets a bit more complex when there are multiple flex items, because
- // flex-shrink is scaled by the flex-basis before it's used as a weight. But
- // even with that scaling, the general principal is that e.g. if the
- // flex-shrink values *sum* to 0.6, then the items will collectively only
- // shrink by 60% (and hence will still overflow).
- // Basic cases where flex-grow sum is less than 1:
- {
- items:
- [
- {
- "flex": "0 0.1 300px",
- "_main-size": [ null, "290px" ] // +10% of (negative) free space
- },
- ]
- },
- {
- items:
- [
- {
- "flex": "0 0.8 400px",
- "_main-size": [ null, "240px" ] // +80% of (negative) free space
- },
- ]
- },
- // ...now with two flex items, with the same flex-basis value:
- {
- items:
- [
- {
- "flex": "0 0.4 150px",
- "_main-size": [ null, "110px" ] // +40% of (negative) free space
- },
- {
- "flex": "0 0.2 150px",
- "_main-size": [ null, "130px" ] // +20% of (negative) free space
- },
- ]
- },
- // ...now with two flex items, with different flex-basis values (and hence
- // differently-scaled flex factors):
- {
- items:
- [
- {
- "flex": "0 0.3 100px",
- "_main-size": [ null, "76px" ]
- },
- {
- "flex": "0 0.1 200px",
- "_main-size": [ null, "184px" ]
- }
- ]
- // Notes:
- // - Free space: -100px
- // - Sum of flex-shrink factors: 0.3 + 0.1 = 0.4
- // - Since that sum ^ is < 1, we'll only distribute that fraction of
- // the free space. We'll distribute: -100px * 0.4 = -40px
- //
- // - 1st item's scaled flex factor: 0.3 * 100px = 30
- // - 2nd item's scaled flex factor: 0.1 * 200px = 20
- // - 1st item's share of distributed free space: 30/(30+20) = 60%
- // - 2nd item's share of distributed free space: 20/(30+20) = 40%
- //
- // SO:
- // - 1st item gets 60% * -40px = -24px. 100px-24px = 76px
- // - 2nd item gets 40% * -40px = -16px. 200px-16px = 184px
- },
- // ...now with min-size modifying how much one item can shrink:
- {
- items:
- [
- {
- "flex": "0 0.3 100px",
- "_main-size": [ null, "70px" ]
- },
- {
- "flex": "0 0.1 200px",
- "_min-main-size": "190px",
- "_main-size": [ null, "190px" ]
- }
- ]
- // Notes:
- // - We proceed as in previous testcase, but clamp the second flex item
- // at its min main size.
- // - After that point, we have a total flex-shrink of = 0.3, so we
- // distribute 0.3 * -100px = -30px to the remaining unfrozen flex
- // items. Since there's only one unfrozen item left, it gets all of it.
- },
- // ...now with min-size larger than our flex-basis:
- // (This makes us freeze the second item right away, before we compute
- // the initial free space.)
- {
- items:
- [
- {
- "flex": "0 0.3 100px",
- "_main-size": [ null, "55px" ] // +30% of 200px-100px-250px
- },
- {
- "flex": "0 0.1 200px",
- "_min-main-size": "250px",
- "_main-size": [ null, "250px" ] // immediately frozen
- }
- ]
- // (Same as previous example, except the min-main-size prevents the
- // second item from shrinking at all)
- },
- // ...and now with a min-size and a small flex-basis, such that we initially
- // have positive free space, which makes the "% of [original] free space"
- // calculations a bit more subtle. We set the "original free space" after
- // we've clamped the second item (the first time the free space is negative).
- {
- items:
- [
- {
- "flex": "0 0.3 100px",
- "_main-size": [ null, "70px" ]
- },
- {
- "flex": "0 0.1 50px",
- "_min-main-size": "200px",
- "_main-size": [ null, "200px" ]
- }
- ]
- },
- // Now with max-size making an item shrink more than its flex-shrink value
- // calls for:
- {
- items:
- [
- {
- "flex": "0 0.3 100px",
- "_main-size": [ null, "70px" ]
- },
- {
- "flex": "0 0.1 200px",
- "_max-main-size": "150px",
- "_main-size": [ null, "150px" ]
- }
- ]
- // Notes:
- // - We proceed as in an earlier testcase, but clamp the second flex item
- // at its max main size.
- // - After that point, we have a total flex-shrink of = 0.3, so we
- // distribute 0.3 * -100px = -30px to the remaining unfrozen flex
- // items. Since there's only one unfrozen item left, it gets all of it.
- },
- // ...and now with a small enough max-size that it prevents the other flex
- // item from taking its full desired portion of the (negative) original free
- // space:
- {
- items:
- [
- {
- "flex": "0 0.3 100px",
- "_main-size": [ null, "90px" ]
- },
- {
- "flex": "0 0.1 200px",
- "_max-main-size": "110px",
- "_main-size": [ null, "110px" ]
- }
- ]
- // Notes:
- // - We proceed as in an earlier testcase, but clamp the second flex item
- // at its max main size.
- // - After that point, we have a total flex-shrink of 0.3, which would
- // have us distribute 0.3 * -100px = -30px to the (one) remaining
- // unfrozen flex item. But our remaining free space is only -10px at
- // that point, so we distribute that instead.
- },
- // ...and now with a small enough max-size that it pushes the other flex item
- // to actually grow a bit (with custom "flex-grow: 1" for this testcase):
- {
- items:
- [
- {
- "flex": "1 0.3 100px",
- "_main-size": [ null, "120px" ]
- },
- {
- "flex": "1 0.1 200px",
- "_max-main-size": "80px",
- "_main-size": [ null, "80px" ]
- }
- ]
- },
- // In this case, the items' flexibilities don't initially sum to < 1, but they
- // do after we freeze the third item for violating its min-size.
- {
- items:
- [
- {
- "flex": "0 0.3 100px",
- "_main-size": [ null, "76px" ]
- },
- {
- "flex": "0 0.1 150px",
- "_main-size": [ null, "138px" ]
- },
- {
- "flex": "0 0.8 10px",
- "_min-main-size": "40px",
- "_main-size": [ null, "40px" ]
- }
- ]
- // Notes:
- // - We immediately freeze the 3rd item, since we're shrinking and its
- // min size obviously prevents it from shrinking at all. This leaves
- // 200px - 100px - 150px - 40px = -90px of "initial free space".
- //
- // - Our remaining flexible items have a total flex-shrink of 0.4,
- // so we can distribute a total of 0.4 * -90px = -36px
- //
- // - We distribute that space using *scaled* flex factors:
- // * 1st item's scaled flex factor: 0.3 * 100px = 30
- // * 2nd item's scaled flex factor: 0.1 * 150px = 15
- // ...which means...
- // * 1st item's share of distributed free space: 30/(30+15) = 2/3
- // * 2nd item's share of distributed free space: 15/(30+15) = 1/3
- //
- // SO:
- // - 1st item gets 2/3 * -36px = -24px. 100px - 24px = 76px
- // - 2nd item gets 1/3 * -36px = -12px. 150px - 12px = 138px
- },
- // In this case, the items' flexibilities sum to > 1, in part due to an item
- // that *can't actually shrink* due to its 0 flex-basis (which gives it a
- // "scaled flex factor" of 0). This prevents us from triggering the special
- // behavior for flexibilities that sum to less than 1, and as a result, the
- // first item ends up absorbing all of the free space.
- {
- items:
- [
- {
- "flex": "0 .5 300px",
- "_main-size": [ null, "200px" ]
- },
- {
- "flex": "0 5 0px",
- "_main-size": [ null, "0px" ]
- }
- ]
- },
- // This case is similar to the one above, but with a *barely* nonzero base
- // size for the second item. This should produce a result similar to the case
- // above. (In particular, we should first distribute a very small amount of
- // negative free space to the second item, getting it to approximately zero,
- // and distribute the bulk of the negative free space to the first item,
- // getting it to approximately 200px.)
- {
- items:
- [
- {
- "flex": "0 .5 300px",
- "_main-size": [ null, "200px" ]
- },
- {
- "flex": "0 1 0.01px",
- "_main-size": [ null, "0px" ]
- }
- ]
- },
- // This case is similar to the ones above, but now we've increased the
- // flex-shrink value on the second-item so that it claims enough of the
- // negative free space to go below its min-size (0px). So, it triggers a min
- // violation & is frozen. For the loop *after* the min violation, the sum of
- // the remaining flex items' flex-shrink values is less than 1, so we trigger
- // the special <1 behavior and only distribute half of the remaining
- // (negative) free space to the first item (instead of all of it).
- {
- items:
- [
- {
- "flex": "0 .5 300px",
- "_main-size": [ null, "250px" ]
- },
- {
- "flex": "0 5 0.01px",
- "_main-size": [ null, "0px" ]
- }
- ]
- },
- ];
|