diff --git a/src/builtin/color.rs b/src/builtin/color.rs
index 225f859..1922c35 100644
--- a/src/builtin/color.rs
+++ b/src/builtin/color.rs
@@ -13,10 +13,22 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
     decl!(f "rgb", |args, _| {
         let channels = args.get("channels").unwrap_or(&Value::Null);
         if channels.is_null() {
-            let red: u16 = arg!(args, 0, "red").clone().try_into().unwrap();
-            let green: u16 = arg!(args, 1, "green").clone().try_into().unwrap();
-            let blue: u16 = arg!(args, 2, "blue").clone().try_into().unwrap();
-            Some(Value::Color(Color::from_values(red, green, blue, Number::from(1))))
+            let red = match arg!(args, 0, "red").clone().eval() {
+                Value::Dimension(n, Unit::None) => n,
+                Value::Dimension(n, Unit::Percent) => (n / Number::from(100)) * Number::from(255),
+                _ => todo!("expected either unitless or % number for alpha"),
+            };
+            let green = match arg!(args, 1, "green").clone().eval() {
+                Value::Dimension(n, Unit::None) => n,
+                Value::Dimension(n, Unit::Percent) => (n / Number::from(100)) * Number::from(255),
+                _ => todo!("expected either unitless or % number for alpha"),
+            };
+            let blue = match arg!(args, 2, "blue").clone().eval() {
+                Value::Dimension(n, Unit::None) => n,
+                Value::Dimension(n, Unit::Percent) => (n / Number::from(100)) * Number::from(255),
+                _ => todo!("expected either unitless or % number for alpha"),
+            };
+            Some(Value::Color(Color::from_rgba(red, green, blue, Number::from(1))))
         } else {
             todo!("channels variable in `rgb`")
         }
@@ -24,15 +36,27 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
     decl!(f "rgba", |args, _| {
         let channels = args.get("channels").unwrap_or(&Value::Null);
         if channels.is_null() {
-            let red: u16 = arg!(args, 0, "red").clone().try_into().unwrap();
-            let green: u16 = arg!(args, 1, "green").clone().try_into().unwrap();
-            let blue: u16 = arg!(args, 2, "blue").clone().try_into().unwrap();
+            let red = match arg!(args, 0, "red").clone().eval() {
+                Value::Dimension(n, Unit::None) => n,
+                Value::Dimension(n, Unit::Percent) => (n / Number::from(100)) * Number::from(255),
+                _ => todo!("expected either unitless or % number for alpha"),
+            };
+            let green = match arg!(args, 1, "green").clone().eval() {
+                Value::Dimension(n, Unit::None) => n,
+                Value::Dimension(n, Unit::Percent) => (n / Number::from(100)) * Number::from(255),
+                _ => todo!("expected either unitless or % number for alpha"),
+            };
+            let blue = match arg!(args, 2, "blue").clone().eval() {
+                Value::Dimension(n, Unit::None) => n,
+                Value::Dimension(n, Unit::Percent) => (n / Number::from(100)) * Number::from(255),
+                _ => todo!("expected either unitless or % number for alpha"),
+            };
             let alpha = match arg!(args, 3, "alpha").clone().eval() {
                 Value::Dimension(n, Unit::None) => n,
                 Value::Dimension(n, Unit::Percent) => n / Number::from(100),
                 _ => todo!("expected either unitless or % number for alpha"),
             };
-            Some(Value::Color(Color::from_values(red, green, blue, alpha)))
+            Some(Value::Color(Color::from_rgba(red, green, blue, alpha)))
         } else {
             todo!("channels variable in `rgba`")
         }
diff --git a/src/color/mod.rs b/src/color/mod.rs
index 8487148..6c7319b 100644
--- a/src/color/mod.rs
+++ b/src/color/mod.rs
@@ -144,7 +144,23 @@ impl Color {
         }
     }
 
-    pub fn from_values(red: u16, green: u16, blue: u16, alpha: Number) -> Self {
+    pub fn from_rgba(red: Number, green: Number, blue: Number, alpha: Number) -> Self {
+        macro_rules! clamp {
+            ($channel:ident) => {
+                let $channel = if $channel > Number::from(255) {
+                    255_u16
+                } else if $channel < Number::from(0) {
+                    0_u16
+                } else {
+                    $channel.round().to_integer().to_u16().unwrap()
+                };
+            };
+        }
+
+        clamp!(red);
+        clamp!(green);
+        clamp!(blue);
+
         let repr = if alpha < Number::from(1) {
             format!("rgba({}, {}, {}, {})", red, green, blue, alpha)
         } else if let Ok(c) = ColorName::try_from([red, green, blue]) {
diff --git a/src/value/mod.rs b/src/value/mod.rs
index 2466b10..2a19a54 100644
--- a/src/value/mod.rs
+++ b/src/value/mod.rs
@@ -1,10 +1,7 @@
 #![allow(dead_code, unused_variables)]
-use std::convert::TryInto;
 use std::fmt::{self, Display};
 use std::iter::Iterator;
 
-use num_bigint::BigInt;
-
 use crate::color::Color;
 use crate::common::{ListSeparator, Op, QuoteKind};
 use crate::units::Unit;
@@ -52,25 +49,6 @@ impl Display for Value {
     }
 }
 
-impl TryInto<u16> for Value {
-    type Error = &'static str;
-    fn try_into(self) -> Result<u16, Self::Error> {
-        match self {
-            Self::BinaryOp(..) => self.eval().try_into(),
-            Self::Dimension(n, Unit::Percent) => todo!(),
-            Self::Dimension(n, Unit::None) => {
-                if n >= Number::from(BigInt::from(255)) {
-                    Ok(255)
-                } else {
-                    Ok(n.to_integer().to_str_radix(10).parse().unwrap())
-                }
-            }
-            Self::Dimension(n, _) => Err("Expected `val` to have no units or \"%\"."),
-            _ => Err("expected number"),
-        }
-    }
-}
-
 impl Value {
     pub fn is_null(&self) -> bool {
         self == &Value::Null
diff --git a/tests/color.rs b/tests/color.rs
index 8779888..214eb86 100644
--- a/tests/color.rs
+++ b/tests/color.rs
@@ -46,6 +46,16 @@ test!(
     "a {\n  color: rgb(1, 2, 3);\n}\n",
     "a {\n  color: #010203;\n}\n"
 );
+test!(
+    rgba_percent,
+    "a {\n  color: rgba(159%, 169, 169%, 50%);\n}\n",
+    "a {\n  color: rgba(255, 169, 255, 0.5);\n}\n"
+);
+test!(
+    rgba_percent_round_up,
+    "a {\n  color: rgba(59%, 169, 69%, 50%);\n}\n",
+    "a {\n  color: rgba(150, 169, 176, 0.5);\n}\n"
+);
 test!(
     rgb_double_digits,
     "a {\n  color: rgb(254, 255, 255);\n}\n",