Skip to content

Commit ea0613c

Browse files
Titozzzclaude
andcommitted
Reject percentage radius for circle radial gradients
Per the CSS spec (css-images-3, <radial-size>), a circle's explicit radius must be a <length> - percentages are only valid for ellipses. Browsers reject the whole declaration for values such as radial-gradient(circle 50%, red, blue), while React Native accepted them and rendered an arbitrary interpretation (max of both resolved axes), so the same style silently diverged between native and web. processBackgroundImage now returns no gradient for a circle (explicit or inferred from a single size) whose size is a percentage, matching web behavior. Ellipses with percentage sizes are unaffected. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent adffc11 commit ea0613c

2 files changed

Lines changed: 26 additions & 0 deletions

File tree

packages/react-native/Libraries/StyleSheet/__tests__/processBackgroundImage-itest.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -986,6 +986,23 @@ describe('processBackgroundImage', () => {
986986
expect(result[0].shape).toEqual('ellipse');
987987
});
988988

989+
it('should reject a circle with a percentage radius', () => {
990+
const input = 'radial-gradient(circle 50%, red, blue)';
991+
expect(processBackgroundImage(input)).toEqual([]);
992+
});
993+
994+
it('should reject an inferred circle with a percentage radius', () => {
995+
const input = 'radial-gradient(50%, red, blue)';
996+
expect(processBackgroundImage(input)).toEqual([]);
997+
});
998+
999+
it('should allow percentage sizes for ellipses', () => {
1000+
const input = 'radial-gradient(50% 20%, red, blue)';
1001+
const result = processBackgroundImage(input);
1002+
expect(result[0].shape).toEqual('ellipse');
1003+
expect(result[0].size).toEqual({x: '50%', y: '20%'});
1004+
});
1005+
9891006
it('should handle radial gradient with explicit shape with size', () => {
9901007
const input = 'radial-gradient(circle 100px at center, red, blue 80%)';
9911008
const result = processBackgroundImage(input);

packages/react-native/Libraries/StyleSheet/processBackgroundImage.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -567,6 +567,15 @@ function parseRadialGradientCSSString(
567567
// If a single size is explicitly set and the shape is an ellipse, return null and do not apply any gradient. Same as web.
568568
return null;
569569
}
570+
571+
if (
572+
shape === 'circle' &&
573+
typeof size === 'object' &&
574+
(typeof size.x === 'string' || typeof size.y === 'string')
575+
) {
576+
// A circle radius must be a <length>. Percentages are only valid for ellipses, so return null and do not apply any gradient. Same as web.
577+
return null;
578+
}
570579
}
571580

572581
const colorStops = parseColorStopsCSSString(remainingParts);

0 commit comments

Comments
 (0)