Leading the Django Software Foundation and Building Open Source with Thibaud Colas
Published July 15, 2026
This video features Thibaud Colas at DjangoCon US 2021 in Online.
This talk introduces Kontrasto, a library for Django and Wagtail that automatically improves the contrast of text over images. We’ll look into how it works, how accessibility guidelines define color contrast, and more generally where Django developers’ expertise can be used to improve accessibility.
This talk was presented at: https://2021.djangocon.us/talks/kontrasto-improving-accessibility-with/
LINKS:
Follow Thibaud Colas 👇
On Twitter: https://twitter.com/thibaud_colas
On GitHub: https://github.com/thibaudcolas
Website: https://thib.me/
Follow DjangCon US 👇
https://twitter.com/djangocon
Follow DEFNA 👇
https://twitter.com/defnado
https://www.defna.org/
Video production by the speaker and DjangoCon US 2021 Volunteers.
Thibaud Colas argues that Django and Wagtail should make accessible output the default, just as they increasingly do for security. He presents Kontrasto, a Python-related project for improving the readability of text placed over images by extracting image colours, choosing suitable text and overlay colours, and checking contrast with WCAG 2 and emerging WCAG 3 methods. He compares client-side and server-side processing, noting the trade-off between responsive accuracy and computing and energy costs, and proposes using Wagtail’s focal-point data or accessibility checks to make the approach more efficient without replacing careful image curation and visual design.
Summarised automatically from the transcript.
Automatically transcribed, so expect mistakes in names and technical terms.
Good day, I'm Thibault. My pronouns are he, him, I'm a developer at Torchbox in UK where I'm also part of the core team for a CMS based on Django called Wagtail that you might have heard of Today I'm here to talk about Contrasto, which is a project that's at the intersection of accessibility and Python. And uh quick mention before I start, I want to thank my partner who's looking after our kids while I get to be here And also want to mention the slides for this presentation are available online if you'd like to look at them at your own pace. They are at tibthib. me slash contrasto. Alright, I'll get going. And first of all sharing some context on this project and this one big number, 97.
4 %, that's how many of the world's Top one thousand home pages have basic accessibility issues. This is quite a sobering figure, at least for me. This comes from a study called the Web I'm Million. They run this once a year with automated checks. on all of those pages. And it just shows quite a systemic issue in how we build sites that at least on average so many of them have such basic issues. But I try and see the opportunity in this I suppose and see this as a bit of a North Star so this kind of very big picture goal that's far out in the distance and might be unattainable, but nonetheless
kind of guides your thinking and helps you navigate the landscape. Um yeah, and I try and ask myself how can we do better? Uh obviously with the number being so large there's lots of ways we can do better. Um One I quite like to think about in particular is the consequences of the frameworks we we choose to build sites with. So this table right there shows the number of errors on home pages per framework. They only have a few available and you might disagree with the definition of a framework, but I think nonetheless it's interesting to see the data and for example see that sites built with Rails have much fewer errors, at least on average. And um
basically what I like to uh help make happen is for sites built with Django or Wagtail to have much fewer errors on average. And um yeah, actually making that happen to me in Django, that's first of all about making sure that whatever Django has available out of the box as a default, that's accessible Second, making sure that if someone wants to go out of their way to make something that's as accessible as possible, Django supports those best practices. And finally making sure that the community is aware of any issues or any kind of more advanced patterns they can leverage or more generally aware of accessibility considerations. A good example of this for me is the forms markup that Django
generates. At the moment it's not so great And there definitely is no reason for it not to be a flawless implementation. It's just a matter of you know the framework and contributors taking the time to make that happen. And um yeah I think this is quite similar to how Django approaches security as well, where over time they just refine their implementation. and make sure that again out of the box as a default Django is as secure as possible. And back to accessibility It's not like we have to make up how we go about this anyway. There are quite clear standards both for sites and apps built with Django and also for Django itself as an authoring tool.
And yeah, the same thing goes for Wagtail. So back to contrasto. I think the easiest way to demonstrate it is for me to share screenshots of sites built with Wagtail and Django where I've encountered this problem And it will hopefully become apparent what the issue is we're trying to resolve here. So ah this is so cringe wolfy. So this this screenshot from Nesta um is probably one of the worst examples I have out there. Yeah, I'll leave it unsaid unspoken what the problem is and just leave it for you to guess with perhaps one more example.
Again on one of the websites we built at Torchbox. Yeah, so put simply the text that's overlaid on those images is is very hard to read, it turns out It's not always impossible to read, but there's quite a clear problem of contrast between the color of the text and the image behind it in all of those three examples. Most of the time that's a matter of choosing the right image to go with the visual design of the text. So the most common solution would be to switch to another image. I can demonstrate this by switching to another background here with much more uniform colors but yeah we see as well it's also a matter of visual design make sure that the text is placed
positioned in a part of the image that has relatively uniform colors. So it's an interesting interesting problem to me because it's uh Engaging lots of different aspects of how we build sites, particularly when the site's content like the images is managed by people who don't always have those considerations in mind. But before we get there, I think it's good to go back to the fundamentals and look at the actual requirements for contrast of text. These come from WICAG In my opinion, the best way to demonstrate them and explain them is to look at a tool like Who Can Use that allows you to provide a background color and a text color and it will give you the contrast ratio between these
two colors so this calculation right there comes from WICAG 2. 0 also gives you a WCAG grading And something I really like as well is that it tries and conveys what this combination of color would look like for people with different vision deficiencies Um ultimately the reason why we care about those contrast uh ratios of text over images is so people can actually view the content in a wide range of circumstances. Yeah, another way to demonstrate this quite easily if you don't want to use any kind of custom tool, even in the Chrome Developer Tools, here I'm inspecting this element on Mars, and I've opened the color picker for the text color.
And if I open the accessibility panel right there, I then see those two lines overlaid on the color picker where Basically they represent the contrast thresholds of weak high to the O. So anything above the topmost line is not enough contrast Anything between is a basic AA level contrast and anything below the bottom most line is triple A contrast. I find it quite cool that it's just in there, out of the box. So if we want to make this work on sites , let's look at the common solutions we have implemented in the past. Again we have our example of text being very hard to read.
Here I believe the main problem is simply that the image isn't appropriate at all as a background. So we might switch to another image. That's the most important solution to this problem, making sure that we curate our site's content and use the right images for the job. But even then the placement of the text is quite poor still, so it's also a matter of uh visual design, making sure that perhaps we place the text in areas of the images that are most likely to be uniform. But even then it heavily depends on the actual visual so something else we might choose to do is to apply more advanced styling Here I'm using a CSS property called backdrop filter with a blur filter. What this does is to apply a blur on the back face of the text that sits above the background.
effectively blurring parts of the background that the text is above. Obviously if the background was white this wouldn't help at all to blur the whites but for this kind of color palette here it does make the text much easier to read and yeah considering it's a single line of CSS I'd highly recommend it The only thing to watch out for is that support for Firefox isn't there just yet, but I believe they are enabling this in a Firefox beta quite soon Um and yeah looking at real-world websites again, so the NASA JPL site is one of the sites we've considered this um contrasto type of approach for quite a bit. So We decided not to go with it
and instead we deployed the might of visual design and of the visuals that NASA has access to to create patterns like this where at the top of the page we have a gradient from dark to transparent. We also have a lateral gradient from dark to transparent and the text also has a slight shadow just so it pops out a bit further from the background visually. And honestly yeah with the right combination of visual designs and with the right imagery this works pretty well and This image of Mars and the ingenuity rotor is quite a good example, but even if we look at something that's less suitable like this imagery of ice caps, it still works quite well. And these common solutions can be quite good.
To me the on only issue really is how dependent they are on using the right image and a bit beyond that also the fact that If the image is really is suitable, you'd rather have no kind of dark overlay, dark gradient at all. And on the contrary, when the image isn't suitable, you'd need as thick of a gradient as possible. it's a bit hard to combine these two requirements. So can we fix this with some automation? Well I I like to think we can so back to our Nesta example Here is what Contrasto would achieve. So it's applied those colored overlays to the beyond behind the text and it's also changed the text color from white to black
It does that by first of all extracting the dominant colors from the image and then calculating the contrast of the text in white and black variants deciding which of these two has the highest contrast and then applying those styles on the page. So Nothing too magical, but nonetheless quite a big sequence of manipulations of colors and uh yeah, I I think the effect Definitely doesn't look great in all cases, but the main idea is that it should make it impossible for contrast to be so cool that you can't read the text Another quick example from what we had looked at past. So here it's not as bad, but nonetheless
with the contrasto background color extraction it looks already much more readable. And finally this last image just kind of summarizing how contraster works. So these three areas just show the results against different parts of the visual. here of the lake. If I concentrate on this this middle one here I can see that there are actually four different ways contrasto can work So we'll look at how these four differ differentiate over the next few slides. So yes we can automate this But I found I want to point out nonetheless that it doesn't remove the need to curating images to be appropriate for those patterns And um yeah, it it makes the worst case scenarios at least look readable
and what I quite like as well is that For the scenarios where this pattern of text overlays works well because the background color is uniform, it will still work well with contrasto because of the color extraction matching the image So how it works? Step one, extract the colors from the image. To the left we have this kind of Sunset on mountain view with lots of orange tones and I can see the dominant color is this kind of orange tone. To the right we have a view of the sea, good weather the uh ice over the oce over the sea and dominant color is blue. That's a success.
Um in those cases though we extract the overall dominant color of the whole image. Whereas if we were were to run a contrast to client side, we actually could only target the part of the image where the text is overlaid which obviously will mean um the extracted color would be much more appropriate to where be placed over wherever the text is So this is the first distinction between how contrast to can work either server side with the whole image being analyzed or client side with just the overlaid area. And the second distinction is how we calculate the contrast. So weak act 2. org contrast ratio is really simple
It's just looking at the luminance values of both the light and dark colors and it leads to situations like this where I'm not sure if people have thoughts on which of these two buttons are the most readable between the black and the white over orange or simply which contrast ratio these two buttons would have. If we actually do the calculation, we can see that at least according to weak act2. 0, the black text has much more contrast than the white one. To me, this is quite surprising. I would find the white text over orange much easier to read. And The blog post this is from, they
ran a very s sm small study with 20 people and out of those 20 people with different types of visual deficiencies They found that 61% of participants did find the white text over orange to be more readable. So that's quite interesting to see cases like this where the simplicity of the calculation might be failing us a bit. So that's why I brought WICACT 3. 0 which is still in early draft to this library. because this new calculation first of all attempts to better represent how humans actually perceive colors and it also takes font size and font weight into account well where Well if you think of how readable text is of course that just makes complete sense.
So this is what a WCAX3. org contrast calculator looks like. Again I have my text color and I have my background color and I have a score displayed here in the middle and I have this matrix with different levels of how good the contrast is between the text in the background And then for those rows I have different font weights and text sizes to choose from. So for example for my kind of button scenario I might choose a bold text and in that case I'd need 18. 4 pixel point five pixels of font size at a minimum for this to be a perfect 5 score And if I calculate this for black as well, result is a much smaller score.
And I can also see that there is no way for me to score this perfect 5 anymore. and if I wanted to keep kind of similar-ish font weight I'd need the text to be slightly bigger at 21 pixels. So that's the the second difference Back to client side versus server side, I think it's worth spending a bit more time on the implications of this choice. Client side, the main benefit is you can analyze only the parts of the image where the text is overlaid, which is great. And you can do so whenever the viewport size might change. So it's always responsive and it always works perfectly depending on where the text might move. as the user's browser viewport
change these dimensions. But that does mean that you do this on every user's device whenever an image is displayed, which is inefficient and I'd also even call that wasteful in terms of uh using the users um computer resources. Server-side on the contrary, that's very efficient um in a CMS context or even with Django, you'd do that when the image is saved to your models and you'd be able to persist the dominant colors. extracted from the image in the same models but that means that is quite imprecise because then you're analyzing the whole image and it's obviously not responsive. So When I say efficient, we of course
want to actually look at some numbers. What it comes down to eventually is the computing resources needed to extract those colors from those images. Here we have a screenshot of the Chrome Developer Tools where I am profiling contrasto running on an image and I can see there is this bottleneck of 15 milliseconds to extract the pixels and their colors from the canvas where I've loaded the image to do the processing. So those 15 seconds, milliseconds, that's on a high-end high-end laptop and that's per image per page load, which Yeah, it feels quite wasteful. So we do try and mitigate that by making sure we we lazy load old images, we serve small images, and then we
defer the processing by um using intersection observer APIs. so that we only do the processing once the user is likely to reach the image on the page. We use request idle callback as well to make sure that this Costly processing doesn't interfere with the page's main thread and interaction and we also cache as much as we can on the client side Well, um I think it's worth even if we could mitigate this to look at the actual energy cost of this. So those 15 milliseconds of CPU cycles according to a tool like Greenframe. That equals 2. 5 milliwatt hours of power conception for an image.
If I multiply that by uh a thousand page views for a site, assuming I have one image per page that's 2. 5 kilowatt hours per month and if I know the carbon intensity of electricity production wherever my users might be I can then convert that into a carbon efficiency. So here I have six kilos or thirtepounds per year of carbon impact f of one image per page with one million page views per month. Um is this acceptable In my opinion, not really. It's worth bearing in mind these are all kind of lower bound estimations. I could easily see this being used say 20 times per page on a high value page, like a home page.
and this would be used on much lower end devices than than my laptop and you also have to bear in mind the performance cost to the user who might suddenly wonder why their um device is getting more sluggish suddenly and might decide to replace it. Yeah quick look at the server side numbers as well. It's 10 times slower at least on my laptop but since it happens as part of image uploads it eventually runs down to zero per each page per page view so to me that's really no no problem whatsoever So this this isn't this isn't uh I I think it's good to try and finish on like what's the best way I could see this work.
That's the most uh mindful both of the effect we want to achieve for people who want to uh have more more readable text over images but also who wants to be conscious of the energy impact of the the sites and the features they build. So Back to Wagtail. In Wagtail we actually already have a way for people in the CMS to define which area of the image is the most important region. And I think it's quite interesting to consider the corollary of this, which is that we also now know where the background overall of the image is. So in this case, rather than extract the color of where the text is, we could still process this server side by extracting the color of areas of the image that aren't the subjects in the image.
And it's easy as well to envision this being done with computer vision as well, something like OpenCV, so that you can automatically detect where the features are of the image and exclude those areas from the color extraction. And to keep the most use of the client-side version of this as well, I think the best way for that to happen would be in a kind of um automated accessibility check scenario where someone uh making a new version of their page changing an image would look at this kind of screen where they have feedback on the accessibility of the page and there might be something that runs the calculation there only for those CMS users to see oh this is how uh the contrast of the text with this image underneath uh
scores and do you want to confirm or do you want to apply another color for those kinds of overlays So yeah, there are options that are quite good on both sides in my opinion, just need to be developed a bit more. And these options actually are based on again existing standards. existing tools and also well worth mentioning that there are research projects looking into this. So what I'd like to leave you with now is again coming back to this big number and quite simply reflecting on the consequences of our actions as developers on on numbers like these and the reality they represent for people actually accessing the sites. And um yeah, that's the last question, just asking ourselves
what else could we do to improve the accessibility of sites because we have Django? Thank you.
Choose imagery with suitable, relatively uniform areas behind the text and position the text carefully. You can also use CSS such as `backdrop-filter`, gradients, overlays, or text shadows; automated contrast handling can help with unsuitable images but does not replace image curation.
Discussed at 8:16Contrasto analyzes an image’s dominant colors, checks white and black text against them, chooses the higher-contrast option, and applies an appropriate overlay and text color. Its goal is to prevent text over images from becoming unreadable, especially in poor-case scenarios.
Discussed at 11:26It can use the WCAG 2 contrast ratio based on luminance, or the newer WCAG 3 approach, which is intended to better reflect human color perception and also considers font size and weight. Client-side processing can analyze the exact area behind the text, while server-side processing generally analyzes the whole image.
Discussed at 14:33Client-side analysis is responsive and can target the text’s actual position, but it repeats work on every user’s device. Server-side analysis is more efficient because results can be saved when an image is uploaded, although analyzing the whole image is less precise and not responsive to layout changes.
Discussed at 16:50In the speaker’s profiling, extracting image pixels took about 15 milliseconds per image on a high-end laptop, estimated at roughly 2.5 milliwatt-hours of energy per image. Lazy loading, smaller images, deferred processing, idle callbacks, and client-side caching can reduce the impact, but server-side processing avoids a per-page-view cost.
Discussed at 18:23Note: We understand that names change, people change, and bodies change. We respect each individual's journey and privacy. If you have any concerns about a video or need us to remove content, please don't hesitate to contact us. We will handle your request with care and promptly address any issues.
Published July 15, 2026
Published July 15, 2026
Published July 15, 2026
Published July 15, 2026
Published July 15, 2026
Published July 14, 2026