diff --git a/Tests/LibWeb/Text/expected/canvas/fillStyle-serialization.txt b/Tests/LibWeb/Text/expected/canvas/fillStyle-serialization.txt
new file mode 100644
index 00000000000..4668e2a5939
--- /dev/null
+++ b/Tests/LibWeb/Text/expected/canvas/fillStyle-serialization.txt
@@ -0,0 +1,5 @@
+`green` -> `#008000`
+`rgba(128, 128, 128, 0.4)` -> `rgba(128, 128, 128, 0.4)`
+`rgba(128, 128, 128, 0)` -> `rgba(128, 128, 128, 0)`
+`rgba(128, 128, 128, 1)` -> `#808080`
+`rgb(128, 128, 128)` -> `#808080`
diff --git a/Tests/LibWeb/Text/expected/canvas/fillstyle.txt b/Tests/LibWeb/Text/expected/canvas/fillstyle.txt
index df993731f86..855bcb42cb8 100644
--- a/Tests/LibWeb/Text/expected/canvas/fillstyle.txt
+++ b/Tests/LibWeb/Text/expected/canvas/fillstyle.txt
@@ -1,5 +1,5 @@
-1. "#00ff00ff"
-2. "#ff0000ff"
-3. "#0000ffff"
-4. "#00ff00ff"
-5. "#ff0000ff"
+1. "#00ff00"
+2. "#ff0000"
+3. "#0000ff"
+4. "#00ff00"
+5. "#ff0000"
diff --git a/Tests/LibWeb/Text/input/canvas/fillStyle-serialization.html b/Tests/LibWeb/Text/input/canvas/fillStyle-serialization.html
new file mode 100644
index 00000000000..c823232e387
--- /dev/null
+++ b/Tests/LibWeb/Text/input/canvas/fillStyle-serialization.html
@@ -0,0 +1,18 @@
+
+
+
diff --git a/Userland/Libraries/LibGfx/Color.cpp b/Userland/Libraries/LibGfx/Color.cpp
index 4071543e697..b63904c0d92 100644
--- a/Userland/Libraries/LibGfx/Color.cpp
+++ b/Userland/Libraries/LibGfx/Color.cpp
@@ -23,9 +23,29 @@
namespace Gfx {
-String Color::to_string() const
+String Color::to_string(HTMLCompatibleSerialization html_compatible_serialization) const
{
- return MUST(String::formatted("#{:02x}{:02x}{:02x}{:02x}", red(), green(), blue(), alpha()));
+ // If the following conditions are all true:
+
+ // 1. The color space is sRGB
+ // NOTE: This is currently always true for Gfx::Color.
+
+ // 2. The alpha is 1
+ // NOTE: An alpha value of 1 will be stored as 255 currently.
+
+ // 3. The RGB component values are internally represented as integers between 0 and 255 inclusive (i.e. 8-bit unsigned integer)
+ // NOTE: This is currently always true for Gfx::Color.
+
+ // 4. HTML-compatible serialization is requested
+ if (alpha() == 255
+ && html_compatible_serialization == HTMLCompatibleSerialization::Yes) {
+ return MUST(String::formatted("#{:02x}{:02x}{:02x}", red(), green(), blue()));
+ }
+
+ // Otherwise, for sRGB the CSS serialization of sRGB values is used and for other color spaces, the relevant serialization of the value.
+ if (alpha() < 255)
+ return MUST(String::formatted("rgba({}, {}, {}, {})", red(), green(), blue(), alpha() / 255.0));
+ return MUST(String::formatted("rgb({}, {}, {})", red(), green(), blue()));
}
String Color::to_string_without_alpha() const
diff --git a/Userland/Libraries/LibGfx/Color.h b/Userland/Libraries/LibGfx/Color.h
index 8d023081425..f00a48b71b9 100644
--- a/Userland/Libraries/LibGfx/Color.h
+++ b/Userland/Libraries/LibGfx/Color.h
@@ -446,7 +446,12 @@ public:
return m_value == other.m_value;
}
- String to_string() const;
+ enum class HTMLCompatibleSerialization {
+ No,
+ Yes,
+ };
+
+ [[nodiscard]] String to_string(HTMLCompatibleSerialization = HTMLCompatibleSerialization::No) const;
String to_string_without_alpha() const;
ByteString to_byte_string() const;
diff --git a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp
index 0c932e45b8b..bdfa04adaf9 100644
--- a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp
+++ b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp
@@ -2847,6 +2847,7 @@ RefPtr Parser::parse_rgb_color_value(TokenStream&
inner_tokens.skip_whitespace();
alpha = parse_number_percentage_value(inner_tokens);
+
inner_tokens.skip_whitespace();
if (inner_tokens.has_next_token())
diff --git a/Userland/Libraries/LibWeb/HTML/Canvas/CanvasState.h b/Userland/Libraries/LibWeb/HTML/Canvas/CanvasState.h
index 547ef519a82..1eb24a3b889 100644
--- a/Userland/Libraries/LibWeb/HTML/Canvas/CanvasState.h
+++ b/Userland/Libraries/LibWeb/HTML/Canvas/CanvasState.h
@@ -63,7 +63,7 @@ public:
{
return m_fill_or_stroke_style.visit(
[&](Gfx::Color color) -> JsFillOrStrokeStyle {
- return color.to_string();
+ return color.to_string(Gfx::Color::HTMLCompatibleSerialization::Yes);
},
[&](auto handle) -> JsFillOrStrokeStyle {
return handle;