Adding -vf scale=out_color_matrix=bt709:out_range=tv to FFmpeg command seems to solve the issue.
"Just in case", we may also mark the stream Metadata as BT.709 and "TV Range":
ffmpeg -y -i duck.gif -vf scale=out_color_matrix=bt709:out_range=tv -pix_fmt yuva420p -bsf:v vp9_metadata=color_space=bt709:color_range=tv duck2.webm
For non-HDR video there are two mainly used color standards: BT.601 and BT.709.
The difference is the conversion matrix from RGB to YUV color space.
There are also two main color ranges for YUV: "TV Range" applies values in range [16, 235], and "PC Range" applies values in range [0, 255].
It looks like FFmpeg uses BT.601 conversion by default (when encoding VP9), while Chrome assumes BT.709 standard (when decoding VP9).
The result is a noticeable "color shift".
For overcoming the issue, we may select "BT.709" and "TV Range" explicitly.
scale=out_color_matrix=bt709:out_range=tv - enforces conversion from RGB to YUV using BT.709 conversion formula, and "TV Range" range.
-bsf:v vp9_metadata=color_space=bt709:color_range=tv sets the stream Metadata to BT.709 and "TV Range" (probably not required).
HTML code used for testing:
<body style="background-color:cornflowerblue">
<img src="duck.gif">
<div>Original GIF</div>
<br><br><br>
<video autoplay loop muted playsinline src="duck2.webm"></video> <div>WebM conversion with bt709 and TV range</div>
<br><br><br>
</body>
Output in Chrome browser:
