webcode-tk 1.2.7__tar.gz → 1.2.8__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {webcode_tk-1.2.7 → webcode_tk-1.2.8}/PKG-INFO +1 -1
- {webcode_tk-1.2.7 → webcode_tk-1.2.8}/pyproject.toml +2 -2
- {webcode_tk-1.2.7 → webcode_tk-1.2.8}/webcode_tk/__init__.py +1 -1
- {webcode_tk-1.2.7 → webcode_tk-1.2.8}/webcode_tk/contrast_tools.py +184 -138
- {webcode_tk-1.2.7 → webcode_tk-1.2.8}/webcode_tk/css_tools.py +2 -4
- {webcode_tk-1.2.7 → webcode_tk-1.2.8}/LICENSE.rst +0 -0
- {webcode_tk-1.2.7 → webcode_tk-1.2.8}/README.rst +0 -0
- {webcode_tk-1.2.7 → webcode_tk-1.2.8}/webcode_tk/animation_tools.py +0 -0
- {webcode_tk-1.2.7 → webcode_tk-1.2.8}/webcode_tk/cascade_tools.py +0 -0
- {webcode_tk-1.2.7 → webcode_tk-1.2.8}/webcode_tk/color_keywords.py +0 -0
- {webcode_tk-1.2.7 → webcode_tk-1.2.8}/webcode_tk/color_tools.py +0 -0
- {webcode_tk-1.2.7 → webcode_tk-1.2.8}/webcode_tk/font_tools.py +0 -0
- {webcode_tk-1.2.7 → webcode_tk-1.2.8}/webcode_tk/html_tools.py +0 -0
- {webcode_tk-1.2.7 → webcode_tk-1.2.8}/webcode_tk/sample_report.json +0 -0
- {webcode_tk-1.2.7 → webcode_tk-1.2.8}/webcode_tk/utils.py +0 -0
- {webcode_tk-1.2.7 → webcode_tk-1.2.8}/webcode_tk/ux_tools.py +0 -0
- {webcode_tk-1.2.7 → webcode_tk-1.2.8}/webcode_tk/validator_tools.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "webcode-tk"
|
|
3
|
-
version = "1.2.
|
|
3
|
+
version = "1.2.8"
|
|
4
4
|
description = "A set of tools for inspecting HTML and CSS code"
|
|
5
5
|
authors = ["hundredvisionsguy <cwinikka@gmail.com>"]
|
|
6
6
|
keywords = ["html", "validation", "css", ]
|
|
@@ -28,7 +28,7 @@ lxml = "^6.0.0"
|
|
|
28
28
|
mechanicalsoup = "^1.4.0"
|
|
29
29
|
pytest-mock = "^3.15.1"
|
|
30
30
|
|
|
31
|
-
[tool.poetry.dev
|
|
31
|
+
[tool.poetry.group.dev.dependencies]
|
|
32
32
|
pytest = "*"
|
|
33
33
|
mkdocs = "*"
|
|
34
34
|
mkgendocs = "*"
|
|
@@ -130,6 +130,7 @@ def generate_contrast_report(
|
|
|
130
130
|
|
|
131
131
|
# Check if fails WCAG level
|
|
132
132
|
result = item.get(wcag_level_key)
|
|
133
|
+
|
|
133
134
|
if result:
|
|
134
135
|
result = result.lower()
|
|
135
136
|
else:
|
|
@@ -154,37 +155,42 @@ def generate_contrast_report(
|
|
|
154
155
|
actual_ratio = item.get("contrast_ratio")
|
|
155
156
|
actual_ratio = round(actual_ratio, 1)
|
|
156
157
|
|
|
157
|
-
|
|
158
|
-
msg
|
|
159
|
-
msg += f"{
|
|
160
|
-
|
|
158
|
+
msg = f"{result}: in {current_file}, the <{element}> element"
|
|
159
|
+
msg += f" WCAG {wcag_level} contrast requirements with a "
|
|
160
|
+
msg += f"ratio of {actual_ratio} (min: {target_ratio})."
|
|
161
|
+
|
|
161
162
|
if msg not in project_files[current_file]:
|
|
162
163
|
project_files[current_file].append(msg)
|
|
163
164
|
|
|
164
165
|
# Check for html docs with no fails.
|
|
165
166
|
for file in project_files:
|
|
166
167
|
errors = project_files.get(file)
|
|
168
|
+
|
|
169
|
+
# Check for global selectors (html, *, or body) and calculate contrast
|
|
170
|
+
global_color_result = css_tools.get_global_color_report(project_path)
|
|
171
|
+
|
|
172
|
+
if isinstance(global_color_result, list):
|
|
173
|
+
for result in global_color_result:
|
|
174
|
+
if file in result:
|
|
175
|
+
# Always add global color failures
|
|
176
|
+
if "fail" in result:
|
|
177
|
+
error_msg = result.split(file)[1]
|
|
178
|
+
msg = f"fail: in {file}, {error_msg.strip()}"
|
|
179
|
+
# Add to errors list if not already there
|
|
180
|
+
if msg not in project_files[file]:
|
|
181
|
+
project_files[file].append(msg)
|
|
182
|
+
|
|
183
|
+
# Now append to report
|
|
167
184
|
if errors:
|
|
168
185
|
if "has no CSS" in errors[0]:
|
|
169
186
|
report.append(errors[0])
|
|
170
187
|
else:
|
|
171
188
|
report.extend(errors)
|
|
172
189
|
else:
|
|
173
|
-
#
|
|
174
|
-
|
|
175
|
-
global_color_result = css_tools.get_global_color_report(
|
|
176
|
-
project_path
|
|
177
|
-
)
|
|
178
|
-
if isinstance(global_color_result, list):
|
|
179
|
-
for result in global_color_result:
|
|
180
|
-
if "fail" in result:
|
|
181
|
-
if file in result:
|
|
182
|
-
error_msg = result.split(file)[1]
|
|
183
|
-
msg = f"fail: in {file}, {error_msg.strip()}"
|
|
184
|
-
else:
|
|
185
|
-
msg = f"pass: {file} passes color contrast."
|
|
186
|
-
|
|
190
|
+
# File has no element-level failures
|
|
191
|
+
msg = f"pass: {file} passes color contrast."
|
|
187
192
|
report.append(msg)
|
|
193
|
+
|
|
188
194
|
return report
|
|
189
195
|
|
|
190
196
|
|
|
@@ -553,8 +559,18 @@ def apply_browser_defaults(
|
|
|
553
559
|
element_styles = {}
|
|
554
560
|
default_specificity = css_tools.get_specificity("")
|
|
555
561
|
|
|
556
|
-
for element in soup.
|
|
557
|
-
|
|
562
|
+
for element in soup.descendants:
|
|
563
|
+
# Skip non-tag elements
|
|
564
|
+
if not isinstance(element, Tag):
|
|
565
|
+
continue
|
|
566
|
+
|
|
567
|
+
# Always include html and body elements for inheritance chain
|
|
568
|
+
is_structural = element.name in ["html", "body"]
|
|
569
|
+
has_text = not element.is_empty_element and element.get_text(
|
|
570
|
+
strip=True
|
|
571
|
+
)
|
|
572
|
+
|
|
573
|
+
if is_structural or has_text:
|
|
558
574
|
# The element object itself becomes the key
|
|
559
575
|
element_styles[element] = {
|
|
560
576
|
"color": {
|
|
@@ -583,6 +599,8 @@ def apply_browser_defaults(
|
|
|
583
599
|
},
|
|
584
600
|
}
|
|
585
601
|
|
|
602
|
+
if element.name in ["html", "body"]:
|
|
603
|
+
print(f" ✓ Added <{element.name}> to element_styles")
|
|
586
604
|
# Apply element-specific defaults
|
|
587
605
|
# Apply link colors
|
|
588
606
|
if element.name == "a":
|
|
@@ -689,8 +707,12 @@ def compute_element_styles(
|
|
|
689
707
|
dict: Dictionary mapping elements to their final computed styles
|
|
690
708
|
after applying CSS cascade and inheritance.
|
|
691
709
|
"""
|
|
692
|
-
#
|
|
693
|
-
computed_styles =
|
|
710
|
+
# ✅ NEW: Shallow copy of dict, deep copy only the style values
|
|
711
|
+
computed_styles = {}
|
|
712
|
+
for element, styles in default_styles.items():
|
|
713
|
+
# Keep the SAME element object (preserves parent relationship)
|
|
714
|
+
# but deep copy its styles dictionary
|
|
715
|
+
computed_styles[element] = copy.deepcopy(styles)
|
|
694
716
|
|
|
695
717
|
# Step 2: Apply all CSS rules (cascade resolution)
|
|
696
718
|
for rules_list in css_rules:
|
|
@@ -1122,145 +1144,144 @@ def apply_inheritance(soup: BeautifulSoup, computed_styles: dict) -> None:
|
|
|
1122
1144
|
def apply_css_inheritance(computed_styles: dict) -> None:
|
|
1123
1145
|
"""
|
|
1124
1146
|
Apply traditional CSS inheritance for inheritable properties.
|
|
1125
|
-
|
|
1126
|
-
Args:
|
|
1127
|
-
computed_styles (dict): Dictionary mapping elements to their
|
|
1128
|
-
computed styles (modified in place).
|
|
1129
|
-
|
|
1130
|
-
Returns:
|
|
1131
|
-
None: Modifies computed_styles dictionary in place.
|
|
1147
|
+
Only inherit from the closest ancestor with an explicit rule.
|
|
1132
1148
|
"""
|
|
1133
1149
|
inheritable_props = {"color", "font-size", "font-weight"}
|
|
1134
1150
|
|
|
1135
|
-
for
|
|
1136
|
-
|
|
1151
|
+
for child_element in computed_styles:
|
|
1152
|
+
child_styles = computed_styles[child_element]
|
|
1137
1153
|
|
|
1138
|
-
#
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
child for child in children if child in computed_styles
|
|
1142
|
-
]
|
|
1154
|
+
# find closest ancestor with explicit value
|
|
1155
|
+
for prop in inheritable_props:
|
|
1156
|
+
child_prop = child_styles.get(prop)
|
|
1143
1157
|
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
#
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1158
|
+
# Skip if child has explicit CSS rule (not default)
|
|
1159
|
+
if child_prop and child_prop.get("source") not in [
|
|
1160
|
+
"default",
|
|
1161
|
+
None,
|
|
1162
|
+
]:
|
|
1163
|
+
continue
|
|
1164
|
+
|
|
1165
|
+
# Walk up tree to find first ancestor with explicit value
|
|
1166
|
+
current = child_element.parent
|
|
1167
|
+
inherited_value = None
|
|
1168
|
+
|
|
1169
|
+
while current and not inherited_value:
|
|
1170
|
+
if current in computed_styles:
|
|
1171
|
+
parent_styles = computed_styles[current]
|
|
1172
|
+
parent_prop = parent_styles.get(prop)
|
|
1173
|
+
|
|
1174
|
+
# Found a parent with this property
|
|
1175
|
+
if parent_prop:
|
|
1176
|
+
# Only inherit if parent has explicit rule
|
|
1177
|
+
if parent_prop.get("source") == "rule":
|
|
1178
|
+
inherited_value = parent_prop
|
|
1179
|
+
inherited_from = current
|
|
1180
|
+
break # ← Stop at first explicit ancestor
|
|
1181
|
+
|
|
1182
|
+
current = current.parent
|
|
1183
|
+
|
|
1184
|
+
# Apply inherited value if found
|
|
1185
|
+
if inherited_value:
|
|
1186
|
+
child_styles[prop] = {
|
|
1187
|
+
"value": inherited_value["value"],
|
|
1188
|
+
"specificity": inherited_value["specificity"],
|
|
1189
|
+
"source": "inheritance",
|
|
1190
|
+
"selector": inherited_value.get("selector", "inherited"),
|
|
1191
|
+
"css_file": inherited_value.get("css_file"),
|
|
1192
|
+
"css_source_type": inherited_value.get("css_source_type"),
|
|
1193
|
+
"inherited_from": inherited_from,
|
|
1194
|
+
}
|
|
1179
1195
|
|
|
1180
1196
|
|
|
1181
1197
|
def apply_visual_background_inheritance(computed_styles: dict) -> None:
|
|
1182
1198
|
"""
|
|
1183
|
-
Apply visual background colors to elements without explicit
|
|
1184
|
-
backgrounds.
|
|
1199
|
+
Apply visual background colors to elements without explicit backgrounds.
|
|
1185
1200
|
|
|
1186
1201
|
Args:
|
|
1187
1202
|
computed_styles: a dictionary of elements with computed styles.
|
|
1188
1203
|
Returns:
|
|
1189
1204
|
None
|
|
1190
1205
|
"""
|
|
1191
|
-
# Track which elements got new backgrounds this iteration
|
|
1192
|
-
changes_made = True
|
|
1193
|
-
max_iterations = 10 # Prevent infinite loops
|
|
1194
|
-
iteration = 0
|
|
1195
|
-
|
|
1196
|
-
while changes_made and iteration < max_iterations:
|
|
1197
|
-
changes_made = False
|
|
1198
|
-
iteration += 1
|
|
1199
|
-
|
|
1200
|
-
for element in computed_styles:
|
|
1201
|
-
element_styles = computed_styles[element]
|
|
1202
1206
|
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
continue
|
|
1206
|
-
|
|
1207
|
-
# Check for explicit backgrounds
|
|
1208
|
-
if "background" in element_styles:
|
|
1209
|
-
bg_value = element_styles["background"]["value"]
|
|
1207
|
+
for element in computed_styles:
|
|
1208
|
+
element_styles = computed_styles[element]
|
|
1210
1209
|
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
element_styles["background-color"] = {
|
|
1215
|
-
"value": None, # No usable color
|
|
1216
|
-
"specificity": "000",
|
|
1217
|
-
"contrast_analysis": "indeterminate",
|
|
1218
|
-
"reason": "background_image_blocks_color_analysis",
|
|
1219
|
-
"original_background": bg_value,
|
|
1220
|
-
"visual_inheritance": False,
|
|
1221
|
-
}
|
|
1222
|
-
changes_made = True
|
|
1223
|
-
continue
|
|
1224
|
-
else:
|
|
1225
|
-
# Has usable background shorthand - skip inheritance
|
|
1226
|
-
continue
|
|
1210
|
+
# Check for BOTH background-color AND background
|
|
1211
|
+
current_bg = element_styles.get("background-color")
|
|
1212
|
+
has_background_shorthand = "background" in element_styles
|
|
1227
1213
|
|
|
1228
|
-
|
|
1229
|
-
|
|
1214
|
+
# If element has background shorthand, process it for images
|
|
1215
|
+
if has_background_shorthand:
|
|
1216
|
+
bg_value = element_styles["background"]["value"]
|
|
1230
1217
|
|
|
1231
|
-
if
|
|
1232
|
-
|
|
1218
|
+
# Check if background contains a raster image
|
|
1219
|
+
if contains_raster_image(bg_value):
|
|
1220
|
+
# Mark as contrast-indeterminate - cannot analyze
|
|
1233
1221
|
element_styles["background-color"] = {
|
|
1234
1222
|
"value": None,
|
|
1235
1223
|
"specificity": "000",
|
|
1236
1224
|
"contrast_analysis": "indeterminate",
|
|
1237
|
-
"reason":
|
|
1238
|
-
"
|
|
1239
|
-
"
|
|
1240
|
-
"original_background": ancestor_bg.get(
|
|
1241
|
-
"original_background"
|
|
1242
|
-
),
|
|
1225
|
+
"reason": "background_image_blocks_color_analysis",
|
|
1226
|
+
"original_background": bg_value,
|
|
1227
|
+
"visual_inheritance": False,
|
|
1243
1228
|
}
|
|
1244
|
-
|
|
1229
|
+
continue
|
|
1245
1230
|
else:
|
|
1246
|
-
#
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1231
|
+
# Has usable background shorthand - skip inheritance
|
|
1232
|
+
continue
|
|
1233
|
+
if not current_bg:
|
|
1234
|
+
continue
|
|
1235
|
+
|
|
1236
|
+
bg_source = current_bg.get("source")
|
|
1237
|
+
bg_value = current_bg.get("value")
|
|
1238
|
+
|
|
1239
|
+
# Skip elements with explicit CSS rules
|
|
1240
|
+
if bg_source == "rule":
|
|
1241
|
+
continue
|
|
1242
|
+
|
|
1243
|
+
# Only update elements that still have the default white background
|
|
1244
|
+
# This prevents overwriting elements with existing proper backgrounds
|
|
1245
|
+
if bg_source != "default":
|
|
1246
|
+
continue
|
|
1247
|
+
|
|
1248
|
+
# Element needs background inheritance (lines 1120-1141)
|
|
1249
|
+
ancestor_bg = find_ancestor_background(element, computed_styles)
|
|
1250
|
+
|
|
1251
|
+
if not ancestor_bg or ancestor_bg.get("source") == "default":
|
|
1252
|
+
# No explicit background to inherit - keep browser default
|
|
1253
|
+
continue
|
|
1254
|
+
|
|
1255
|
+
if ancestor_bg.get("contrast_analysis") == "indeterminate":
|
|
1256
|
+
# Ancestor is indeterminate - propagate that status
|
|
1257
|
+
element_styles["background-color"] = {
|
|
1258
|
+
"value": None,
|
|
1259
|
+
"specificity": "000",
|
|
1260
|
+
"contrast_analysis": "indeterminate",
|
|
1261
|
+
"reason": ancestor_bg["reason"],
|
|
1262
|
+
"inherited_from": ancestor_bg["source_element"],
|
|
1263
|
+
"source": "visual_inheritance",
|
|
1264
|
+
"original_background": ancestor_bg.get("original_background"),
|
|
1265
|
+
}
|
|
1266
|
+
|
|
1267
|
+
else:
|
|
1268
|
+
# Normal inheritance - extract usable color
|
|
1269
|
+
contrast_color = extract_contrast_color(ancestor_bg["value"])
|
|
1270
|
+
effective_color = (
|
|
1271
|
+
contrast_color if contrast_color else ancestor_bg["value"]
|
|
1272
|
+
)
|
|
1273
|
+
element_styles["background-color"] = {
|
|
1274
|
+
"value": effective_color,
|
|
1275
|
+
"specificity": "000",
|
|
1276
|
+
"source": "visual_inheritance",
|
|
1277
|
+
"inherited_from": ancestor_bg["source_element"],
|
|
1278
|
+
"contrast_analysis": "determinable",
|
|
1279
|
+
"original_background": (
|
|
1280
|
+
ancestor_bg["value"]
|
|
1281
|
+
if ancestor_bg["value"] != DEFAULT_GLOBAL_BACKGROUND
|
|
1282
|
+
else None
|
|
1283
|
+
),
|
|
1284
|
+
}
|
|
1264
1285
|
|
|
1265
1286
|
|
|
1266
1287
|
def has_usable_background_color(background_prop: dict) -> bool:
|
|
@@ -1415,6 +1436,10 @@ def find_ancestor_background(element: Tag, computed_styles: dict) -> dict:
|
|
|
1415
1436
|
# Accept both "rule" and "default" sources
|
|
1416
1437
|
if bg_source in ["rule", "default"]:
|
|
1417
1438
|
bg_value = current_styles[bg_prop]["value"]
|
|
1439
|
+
if bg_source == "default":
|
|
1440
|
+
# Skip ancestors with only default backgrounds
|
|
1441
|
+
skip_ancestor = True
|
|
1442
|
+
break
|
|
1418
1443
|
|
|
1419
1444
|
# Does this ancestor already is indeterminate status
|
|
1420
1445
|
if (
|
|
@@ -1531,6 +1556,26 @@ def analyze_elements_for_contrast(
|
|
|
1531
1556
|
contrast_analysis = element_data["background-color"].get(
|
|
1532
1557
|
"contrast_analysis"
|
|
1533
1558
|
)
|
|
1559
|
+
|
|
1560
|
+
# Check if this element inherited both text and background colors
|
|
1561
|
+
text_color_source_type = extract_property_source(
|
|
1562
|
+
element_data["color"]
|
|
1563
|
+
).get("source_type")
|
|
1564
|
+
bg_color_source_type = extract_property_source(
|
|
1565
|
+
element_data["background-color"]
|
|
1566
|
+
).get("source_type")
|
|
1567
|
+
|
|
1568
|
+
# Determine if this is a global color failure
|
|
1569
|
+
inherited_text = text_color_source_type in [
|
|
1570
|
+
"inherited",
|
|
1571
|
+
"browser_default",
|
|
1572
|
+
]
|
|
1573
|
+
inherited_bg = bg_color_source_type in [
|
|
1574
|
+
"visual_inheritance",
|
|
1575
|
+
"browser_default",
|
|
1576
|
+
]
|
|
1577
|
+
is_global_failure = inherited_text and inherited_bg
|
|
1578
|
+
|
|
1534
1579
|
if is_large:
|
|
1535
1580
|
aaa_results = contrast_report.get("Large AAA")
|
|
1536
1581
|
aa_results = contrast_report.get("Large AA")
|
|
@@ -1562,6 +1607,7 @@ def analyze_elements_for_contrast(
|
|
|
1562
1607
|
"wcag_aa_pass": aa_results,
|
|
1563
1608
|
"wcag_aaa_pass": aaa_results,
|
|
1564
1609
|
"contrast_analysis": contrast_analysis,
|
|
1610
|
+
"global_color_failure": is_global_failure,
|
|
1565
1611
|
}
|
|
1566
1612
|
|
|
1567
1613
|
# add to results
|
|
@@ -1677,5 +1723,5 @@ if __name__ == "__main__":
|
|
|
1677
1723
|
contrast_results = generate_contrast_report(project_path, "AAA")
|
|
1678
1724
|
project_path = "tests/test_files/contrast_tool_test/"
|
|
1679
1725
|
global_colors = css_tools.get_project_global_colors(project_path)
|
|
1680
|
-
print(
|
|
1681
|
-
print(
|
|
1726
|
+
print()
|
|
1727
|
+
print()
|
|
@@ -2488,8 +2488,6 @@ def get_color_data(file: str, color_details: dict, level="aaa") -> tuple:
|
|
|
2488
2488
|
Returns:
|
|
2489
2489
|
color_data: a tuple with filename and results as a string"""
|
|
2490
2490
|
selector = color_details.get("selector")
|
|
2491
|
-
bg_color = color_details.get("background-color")
|
|
2492
|
-
color = color_details.get("color")
|
|
2493
2491
|
contrast_ratio = color_details.get("contrast_ratio")
|
|
2494
2492
|
if level == "aaa":
|
|
2495
2493
|
passes = color_details.get("passes_normal_aaa")
|
|
@@ -2498,8 +2496,8 @@ def get_color_data(file: str, color_details: dict, level="aaa") -> tuple:
|
|
|
2498
2496
|
if passes:
|
|
2499
2497
|
results = "passes global colors"
|
|
2500
2498
|
else:
|
|
2501
|
-
results = f"{selector}
|
|
2502
|
-
results += f" ratio of {contrast_ratio}."
|
|
2499
|
+
results = f"the <{selector}> element fails WCAG {level.upper()}"
|
|
2500
|
+
results += f"contrast with a ratio of {contrast_ratio}."
|
|
2503
2501
|
color_data = (file, results)
|
|
2504
2502
|
return color_data
|
|
2505
2503
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|