Skip to content

Feature: Background Gradient Support#1580

Open
CaptainDario wants to merge 3 commits into
daohoangson:masterfrom
CaptainDario:feature-background_gradient
Open

Feature: Background Gradient Support#1580
CaptainDario wants to merge 3 commits into
daohoangson:masterfrom
CaptainDario:feature-background_gradient

Conversation

@CaptainDario
Copy link
Copy Markdown
Contributor

@CaptainDario CaptainDario commented Apr 7, 2026

I want to make this package render the following HTML correctly.

HTML
<ol class="definition-list" data-count="1" style="--font-size-no-units: 16;--line-height: 1.5;--text-color: #d4d4d4;--text-color-light: #888888;--background-color: #1e1e1e;--border-color: #888888;--link-color: #68b5e9;--list-padding1: 1.4em;--list-padding2: 1.4em;list-style-type: none;padding-left: 0;margin: 0">
  <li class="definition-item" style="margin-bottom: 0.25em; list-style-type: none;">
    <span class="gloss-content" style="display: block;">
      <ul class="gloss-sc-ul" lang="ja" style="padding-left: 1.4em;margin: 0;list-style-type: '*'">
        <li class="gloss-sc-li">
          <span class="gloss-sc-span" style="font-size:0.7em;font-weight:bold;padding:0.15em 0.3em 0.3em 0.3em;word-break:keep-all;border-radius:0.3em;vertical-align:text-bottom;background-color:#565656;color:white;cursor:help;margin:0em 0.25em 0em 0em;" data-sc-code="n" title="noun (common) (futsuumeishi)">noun</span><span class="gloss-sc-span" style="font-size:0.7em;font-weight:bold;padding-top:0.15em;padding-right:0.3em;padding-bottom:0.3em;padding-left:0.3em;word-break:keep-all;border-radius:0.3em;vertical-align:text-bottom;background-color:brown;color:white;cursor:help;margin-right:0.25em;" data-sc-code="uk" title="word usually written using kana alone">kana</span>
          <ol class="gloss-sc-ol" style="padding-left: 1.4em;margin: 0">
            <li class="gloss-sc-li" style="list-style-type:&quot;① &quot;;" data-sc-sense-number="1">
              <ul class="gloss-sc-ul" style="color: #ffff00;padding-left: 1.4em;margin: 0" data-sc-content="glossary">
                <li class="gloss-sc-li">spring</li>
              </ul>
              <ul class="gloss-sc-ul" style="padding-left: 1.4em;margin: 0;margin-bottom: 0.5em">
                <li class="gloss-sc-li" style="list-style-type:circle;font-size:1.20em;" data-sc-content="example-sentence-a" lang="ja">その<span class="gloss-sc-span" style="color:#dd2121;text-shadow:0.5px 0.5px 1px gray;text-emphasis:circle crimson;text-decoration-line:underline;text-decoration-style:wavy;text-decoration-color:red;">ばね</span><ruby class="gloss-sc-ruby"><rt class="gloss-sc-rt">いっ</rt></ruby><ruby class="gloss-sc-ruby"><rt class="gloss-sc-rt"></rt></ruby><ruby class="gloss-sc-ruby"><rt class="gloss-sc-rt">くるま</rt></ruby><ruby class="gloss-sc-ruby"><rt class="gloss-sc-rt">ぜん</rt></ruby><ruby class="gloss-sc-ruby"><rt class="gloss-sc-rt">じゅう</rt></ruby><ruby class="gloss-sc-ruby"><rt class="gloss-sc-rt">りょう</rt></ruby><ruby class="gloss-sc-ruby"><rt class="gloss-sc-rt">ささ</rt></ruby>えている。</li>
                <li class="gloss-sc-li" style="list-style-type:none;font-size:0.70em;" data-sc-content="example-sentence-b" lang="en">That one spring carries the whole weight of the car.</li>
              </ul>
            </li>
          </ol>
        </li>
        <li class="gloss-sc-li">
          <span class="gloss-sc-span" style="font-size:0.7em;font-weight:bold;padding:0.15em 0.3em 0.3em 0.3em;word-break:keep-all;border-radius:0.3em;vertical-align:text-bottom;background-color:#565656;color:white;cursor:help;margin-right:0.25em;" data-sc-code="n" title="noun (common) (futsuumeishi)">noun</span><span class="gloss-sc-span" style="font-size:0.7em;font-weight:bold;padding:0.15em 0.3em 0.3em 0.3em;word-break:keep-all;border-radius:0.3em;vertical-align:text-bottom;background-color:brown;color:white;cursor:help;margin-right:0.25em;" data-sc-code="uk" title="word usually written using kana alone">kana</span><span class="gloss-sc-span" title="valid only for these forms and/or readings" style="cursor:help;"><span class="gloss-sc-span" style="color:red;"></span>ばね・バネ only<span class="gloss-sc-span" style="color:red;"></span></span>
          <ol class="gloss-sc-ol" style="padding-left: 1.4em;margin: 0">
            <li class="gloss-sc-li" style="list-style-type:&quot;② &quot;;" data-sc-sense-number="2">
              <ul class="gloss-sc-ul" style="color: #ffff00;padding-left: 1.4em;margin: 0" data-sc-content="glossary">
                <li class="gloss-sc-li">spring (in one's legs)</li>
                <li class="gloss-sc-li">bounce</li>
              </ul>
            </li>
            <li class="gloss-sc-li" style="list-style-type:&quot;③ &quot;;" data-sc-sense-number="3">
              <ul class="gloss-sc-ul" style="color: #ffff00;padding-left: 1.4em;margin: 0" data-sc-content="glossary">
                <li class="gloss-sc-li">springboard</li>
                <li class="gloss-sc-li">impetus</li>
              </ul>
            </li>
          </ol>
        </li>
        <li class="gloss-sc-li" data-sc-content="forms">
          <span class="gloss-sc-span" title="spelling and reading variants" style="font-size:0.7em;font-weight:bold;padding:0.15em 0.3em 0.3em 0.3em;word-break:keep-all;border-radius:0.3em;vertical-align:text-bottom;background-color:#565656;color:white;cursor:help;margin-right:0.25em;">forms</span>
          <div class="gloss-sc-table-container" style="display: block;overflow-x: auto;">
            <table class="gloss-sc-table" style="table-layout: auto;border-collapse: collapse;border-spacing: 0;color: var(--text-color);">
              <tbody>
                <tr class="gloss-sc-tr">
                  <th class="gloss-sc-th" style="border: 1px solid var(--border-color);padding: 0.25em;vertical-align: top;background-color: #2d2d2d;text-align: center;font-weight: normal"></th>
                  <th class="gloss-sc-th" style="border: 1px solid var(--border-color);padding: 0.25em;vertical-align: top;background-color: #2d2d2d;text-align: center;font-weight: normal;white-space: nowrap">発条</th>
                  <th class="gloss-sc-th" style="border: 1px solid var(--border-color);padding: 0.25em;vertical-align: top;background-color: #2d2d2d;text-align: center;font-weight: normal;white-space: nowrap">弾機</th>
                  <th class="gloss-sc-th" style="border: 1px solid var(--border-color);padding: 0.25em;vertical-align: top;background-color: #2d2d2d;text-align: center;font-weight: normal;white-space: nowrap">撥条</th>
                  <th class="gloss-sc-th" style="border: 1px solid var(--border-color);padding: 0.25em;vertical-align: top;background-color: #2d2d2d;text-align: center;font-weight: normal"><span class="gloss-sc-span" title="no associated kanji forms" style="color:red;cursor:help;"></span></th>
                </tr>
                <tr class="gloss-sc-tr">
                  <th class="gloss-sc-th" style="border: 1px solid var(--border-color);padding: 0.25em;vertical-align: top;background-color: #2d2d2d;font-weight: normal"><span class="gloss-sc-span" title="gikun (meaning as reading) or jukujikun (special kanji reading)" style="cursor:help;"><span class="gloss-sc-span" style="color:red;"></span>ばね<span class="gloss-sc-span" style="color:red;"></span></span></th>
                  <td class="gloss-sc-td" style="border: 1px solid var(--border-color);padding: 0.25em;vertical-align: top;text-align: center"><span class="gloss-sc-span" title="high priority form" style="padding:0.15em 0.2em;border-radius:1.00em;cursor:help;background-color:green;color:white;"></span></td>
                  <td class="gloss-sc-td" style="border: 1px solid var(--border-color);padding: 0.25em;vertical-align: top;text-align: center"><span class="gloss-sc-span" title="valid form/reading combination" style="padding:0.15em 0.2em;border-radius:1.00em;cursor:help;background-color:transparent;border-style:solid;border-width:0.75px;"></span></td>
                  <td class="gloss-sc-td" style="border: 1px solid var(--border-color);padding: 0.25em;vertical-align: top;text-align: center"><span class="gloss-sc-span" title="rarely used form" style="padding:0.15em 0.2em;border-radius:1.00em;cursor:help;background-color:purple;color:white;"></span></td>
                  <td class="gloss-sc-td" style="border: 1px solid var(--border-color);padding: 0.25em;vertical-align: top;text-align: center"></td>
                </tr>
                <tr class="gloss-sc-tr">
                  <th class="gloss-sc-th" style="border: 1px solid var(--border-color);padding: 0.25em;vertical-align: top;background-color: #2d2d2d;font-weight: normal">ぜんまい</th>
                  <td class="gloss-sc-td" style="border: 1px solid var(--border-color);padding: 0.25em;vertical-align: top;text-align: center"><span class="gloss-sc-span" title="valid form/reading combination" style="padding:0.15em 0.2em;border-radius:1.00em;cursor:help;background-color:transparent;border-style:solid;border-width:0.75px;"></span></td>
                  <td class="gloss-sc-td" style="border: 1px solid var(--border-color);padding: 0.25em;vertical-align: top;text-align: center"></td>
                  <td class="gloss-sc-td" style="border: 1px solid var(--border-color);padding: 0.25em;vertical-align: top;text-align: center"><span class="gloss-sc-span" title="rarely used form" style="padding:0.15em 0.2em;border-radius:1.00em;cursor:help;background:radial-gradient(purple 0.55em, black 1.00em);color:white;"></span></td>
                  <td class="gloss-sc-td" style="border: 1px solid var(--border-color);padding: 0.25em;vertical-align: top;text-align: center"></td>
                </tr>
                <tr class="gloss-sc-tr">
                  <th class="gloss-sc-th" style="border: 1px solid var(--border-color);padding: 0.25em;vertical-align: top;background-color: #2d2d2d;font-weight: normal">はつじょう</th>
                  <td class="gloss-sc-td" style="border: 1px solid var(--border-color);padding: 0.25em;vertical-align: top;text-align: center"><span class="gloss-sc-span" title="valid form/reading combination" style="padding:0.15em 0.2em;border-radius:1.00em;cursor:help;background-color:transparent;border-style:solid;border-width:0.75px;"></span></td>
                  <td class="gloss-sc-td" style="border: 1px solid var(--border-color);padding: 0.25em;vertical-align: top;text-align: center"></td>
                  <td class="gloss-sc-td" style="border: 1px solid var(--border-color);padding: 0.25em;vertical-align: top;text-align: center">
                    <div class="gloss-sc-div" title="rarely used form" style="clip-path:circle();cursor:help;background-color:purple;color:white;"></div>
                  </td>
                  <td class="gloss-sc-td" style="border: 1px solid var(--border-color);padding: 0.25em;vertical-align: top;text-align: center"></td>
                </tr>
                <tr class="gloss-sc-tr">
                  <th class="gloss-sc-th" style="border: 1px solid var(--border-color);padding: 0.25em;vertical-align: top;background-color: #2d2d2d;font-weight: normal">だんき</th>
                  <td class="gloss-sc-td" style="border: 1px solid var(--border-color);padding: 0.25em;vertical-align: top;text-align: center"></td>
                  <td class="gloss-sc-td" style="border: 1px solid var(--border-color);padding: 0.25em;vertical-align: top;text-align: center"><span class="gloss-sc-span" title="valid form/reading combination" style="padding:0.15em 0.2em;border-radius:1.00em;cursor:help;background-color:transparent;border-style:solid;border-width:0.75px;"></span></td>
                  <td class="gloss-sc-td" style="border: 1px solid var(--border-color);padding: 0.25em;vertical-align: top;text-align: center"></td>
                  <td class="gloss-sc-td" style="border: 1px solid var(--border-color);padding: 0.25em;vertical-align: top;text-align: center"></td>
                </tr>
                <tr class="gloss-sc-tr">
                  <th class="gloss-sc-th" style="border: 1px solid var(--border-color);padding: 0.25em;vertical-align: top;background-color: #2d2d2d;font-weight: normal">バネ</th>
                  <td class="gloss-sc-td" style="border: 1px solid var(--border-color);padding: 0.25em;vertical-align: top;text-align: center"></td>
                  <td class="gloss-sc-td" style="border: 1px solid var(--border-color);padding: 0.25em;vertical-align: top;text-align: center"></td>
                  <td class="gloss-sc-td" style="border: 1px solid var(--border-color);padding: 0.25em;vertical-align: top;text-align: center"></td>
                  <td class="gloss-sc-td" style="border: 1px solid var(--border-color);padding: 0.25em;vertical-align: top;text-align: center"><span class="gloss-sc-span" title="valid form/reading combination" style="padding:0.15em 0.2em;border-radius:1.00em;cursor:help;background-color:transparent;border-style:solid;border-width:0.75px;"></span></td>
                </tr>
              </tbody>
            </table>
          </div>
        </li>
      </ul>
    </span>
  </li>
</ol>

Comparison

Goal Current PR
goal current image

This PR's goal

Parsing CSS background-image gradient.

What's supported

All six CSS gradient functions: linear-gradient, radial-gradient, conic-gradient, and their repeating-* variants. Supports angle units (deg/rad/grad/turn), to <side/corner> directions, from <angle> / at <position> hints, circle/ellipse shape keywords, and color stops with % or angle positions. Colors delegate to existing tryParseColor(). Ellipse radial gradients and conic gradients apply a GradientTransform at paint time for correct CSS-spec sizing and coordinate alignment.


CSS value Example HTML Flutter
linear-gradient to bottom linear-gradient(to bottom, #e74c3c, #3498db)
View<div style="width:200px;height:100px;background:linear-gradient(to bottom,#e74c3c,#3498db)"></div>
to_bottom
linear-gradient to right linear-gradient(to right, #e74c3c, #3498db)
View<div style="width:200px;height:100px;background:linear-gradient(to right,#e74c3c,#3498db)"></div>
to_right
linear-gradient 45deg linear-gradient(45deg, #e74c3c, #f39c12, #3498db)
View<div style="width:200px;height:100px;background:linear-gradient(45deg,#e74c3c,#f39c12,#3498db)"></div>
45deg
linear-gradient to bottom right linear-gradient(to bottom right, #e74c3c, #3498db)
View<div style="width:200px;height:100px;background:linear-gradient(to bottom right,#e74c3c,#3498db)"></div>
to_bottom_right
linear-gradient explicit stops linear-gradient(to right, #e74c3c 0%, #f39c12 50%, #3498db 100%)
View<div style="width:200px;height:100px;background:linear-gradient(to right,#e74c3c 0%,#f39c12 50%,#3498db 100%)"></div>
explicit_stops
linear-gradient transparent linear-gradient(to right, transparent, #3498db)
View<div style="width:200px;height:100px;background:linear-gradient(to right,transparent,#3498db)"></div>
transparent
repeating-linear-gradient repeating-linear-gradient(to right, #e74c3c 0%, #3498db 20%)
View<div style="width:200px;height:100px;background:repeating-linear-gradient(to right,#e74c3c 0%,#3498db 20%)"></div>
repeating-linear
radial-gradient default ellipse radial-gradient(#e74c3c, #3498db)
View<div style="width:200px;height:100px;background:radial-gradient(#e74c3c,#3498db)"></div>
default_ellipse
radial-gradient circle radial-gradient(circle, #e74c3c, #3498db)
View<div style="width:200px;height:100px;background:radial-gradient(circle,#e74c3c,#3498db)"></div>
circle
radial-gradient circle at top right radial-gradient(circle at top right, #e74c3c, #3498db)
View<div style="width:200px;height:100px;background:radial-gradient(circle at top right,#e74c3c,#3498db)"></div>
circle_at_top_right
radial-gradient ellipse at bottom left radial-gradient(at bottom left, #e74c3c, #3498db)
View<div style="width:200px;height:100px;background:radial-gradient(at bottom left,#e74c3c,#3498db)"></div>
at_bottom_left
repeating-radial-gradient repeating-radial-gradient(circle, #e74c3c 0%, #3498db 20%)
View<div style="width:200px;height:100px;background:repeating-radial-gradient(circle,#e74c3c 0%,#3498db 20%)"></div>
repeating-radial
conic-gradient default conic-gradient(#e74c3c, #f39c12, #2ecc71, #3498db)
View<div style="width:200px;height:100px;background:conic-gradient(#e74c3c,#f39c12,#2ecc71,#3498db)"></div>
default
conic-gradient from 45deg conic-gradient(from 45deg, #e74c3c, #3498db)
View<div style="width:200px;height:100px;background:conic-gradient(from 45deg,#e74c3c,#3498db)"></div>
from_45deg
conic-gradient at top left conic-gradient(at top left, #e74c3c, #3498db)
View<div style="width:200px;height:100px;background:conic-gradient(at top left,#e74c3c,#3498db)"></div>
at_top_left
conic-gradient explicit stops conic-gradient(#e74c3c 0deg, #f39c12 90deg, #2ecc71 180deg, #3498db 360deg)
View<div style="width:200px;height:100px;background:conic-gradient(#e74c3c 0deg,#f39c12 90deg,#2ecc71 180deg,#3498db 360deg)"></div>
explicit_stops
repeating-conic-gradient repeating-conic-gradient(from 0deg, #e74c3c 0%, #3498db 25%)
View<div style="width:200px;height:100px;background:repeating-conic-gradient(from 0deg,#e74c3c 0%,#3498db 25%)"></div>
repeating-conic

Limitations

  • Length-based color stop positions (px, em, rem, etc.) are not supported — only % and angle units. Stops using length units fall back to auto-distributed positions, which will produce wrong colors for gradients like radial-gradient(purple 0.55em, black 1em).
  • Percentage/length at <position> values (e.g. at 30% 70%) fall back to center.
  • CSS closest-side, closest-corner, farthest-side size keywords for radial gradients are ignored; farthest-corner sizing is always applied.

Tests

43 unit tests covering every parser branch + 17 golden rendering tests (linear, radial, conic, each repeating variant) in a 200×100 box.

@CaptainDario CaptainDario marked this pull request as ready for review April 8, 2026 00:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant