Microsoft Power BI rose to its leading position in the BI market on the back of its top-shelf PowerQuery self-service ETL and VertiPaq in-memory engine as well as its familiarity and integration for Office and Azure users. On the other hand, its competitive strength has never been on the visualization side, especially compared with Tableau’s polish and advanced controls. That is slowly improving, with additions like Charticulator going in the right direction. But overall, most Power BI reports tend to look the same, and the common way to make them look more dynamic and responsive to user input, like an app would, involves time-consuming and clunky use of bookmarks and images. I’ve done it when I really needed to, but I can’t say I enjoy the authoring experience.
Namely, the HTML Content custom visual can interpret CSS, including via inline styling. In most cases, when CSS is used to build websites, it’s a best practice to put CSS in a separate file. In our case, inline CSS is preferred as it will let us inject data via PowerQuery or better, DAX. Let’s see what that looks like with a quick proof of concept.
1. Dynamic CSS in Power BI, Step by Step
A straightforward way to use HTML Content is to generate your HTML code in PowerQuery, for instance in a disconnected table where you could set up a list of reusable snippets. But things get really interesting thanks to HTML Content’s ability to display not only static columns but also DAX measures. This means that you can inject variables into your CSS, opening a range of possibilities.
For our proof of concept, let’s take this CSS gradient then empty out it angles to replace them with a DAX calculation, which means that the entire gradient is recomputed based on the most common Power BI user interaction: (cross) filtering.
CSS = VAR Angle = [Impact Score Average] *36 RETURN "<div style='height: 100vh; background: linear-gradient(" & Angle & "deg, #FFB7B7 0%, #727272 100%), radial-gradient(60.91% 100% at 50% 0%, #FFD1D1 0%, #260000 100%), linear-gradient(" & Angle & "deg, #FFDDDD 0%, #720066 100%), linear-gradient(" & Angle & "deg, #00FFFF 0%, #FF4444 100%), radial-gradient(100.22% 100% at 70.57% 0%, #FF0000 0%, #00FFE0 100%), linear-gradient(127.43deg, #B7D500 0%, #3300FF 100%); background-blend-mode: screen, overlay, hard-light, color-burn, color-dodge, normal;'></div>"
A couple of things to notice in the code above:
- We’re using double quotes to build our string in DAX, so we want to use single quotes within it in the HTML. This is vastly easier than escaping double quotes.
- height: 100vh sets your main div (the “box” of HTML content you’re filling in) to use its entire height even if it’s empty.
By putting the HTML Content visual at the bottom of the z-index stack (i.e. select it then “Send to Back”), and playing with partial transparency in your other visuals, you can give your entire report page a “vibe” that users will perceive instantly before reading any specific visual.
Once you have a dynamic background that you like, you’ll want to think through how your overall Power BI theme needs to be lined up with it. Tools to get you started:
- The Extract Theme functionality in Adobe Color, in case you worked off someone else’s CSS that came with preexisting colors.
- The Theme Generator at PowerBI.Tips.
You can of course load a completely different stylesheet too, the above is again just a proof of concept.
2. Use Cases: Make it Look More About the Individual Report and Less Like Every Other Power BI Canvas
Now that we’ve established we can do this, should we? What’s the point? Here are some scenarios where I think this technique is worth exploring:
- Big screen dashboards meant to be consumed from a distance rather than interacted with at your desk. Reports displayed on a big TV hanging in the office can’t be designed like they’re going to be read, the 10-feet-away experience is completely distinct.
- This instant “mood” that you can convey with smart use of CSS can work well for operational status reports where you want the team to know whether they’re behind, at, or above their goal. Are we killing it or are we getting slaughtered? Is there an emergency to address? Giving that instant visual feedback would also benefit What If scenarios.
- Reports that have a strong branding requirement. You might see this more in FMCG companies where branding and product packaging are core company values. Of course, this needs to be healthily balanced with usability and accessibility concerns, but some users/customers will want to see their logo and color scheme heavily reflected on their reports, and you’re just not going to change their mind. Roll with it and make it work, or resist it and they’ll get someone else to do it.
- Organizations where Power BI is already heavily deployed with every report looking the same (“wait, which report am I even looking at again?”), and they’re looking for a bit of a visual makeover. I myself tend to make very utilitarian reports where every pixel needs to matter. But what if the intended audience will actually engage more with a bit of visual glamour? The reality is that people get bored with reports that look like IT designed them.
- Visual elements that would be time consuming to generate and handle as images or SVG. Because CSS is code, it inherently gives you more dynamic control than having to load static assets like GIFs.
3. Known Limitations: I’ll Admit This is A Bit Cutting Edge
Like most things, this technique comes with its set of tradeoffs, so better walk into it informed of its drawbacks:
- HTML Content is not and cannot be certified, so all limitations of non-certified custom visuals apply: no print, no export to PDF etc.
- Power BI’s sandboxing rules can get in the way, read this for details.
- Support for advanced CSS techniques varies among browsers. If you have to support users stuck with ancient versions of Internet Explorer, things can get pretty hairy.
- Power BI Desktop may or may not render your CSS the way actual browsers will. You will need to doublecheck how things work in the service.
- Most Power BI developers and business analysts don’t know CSS, these are different skillsets. Be prepared to learn, leverage online resources, or work with a web designer. Or you can hire me.
- Expression-based control of partial transparency for visuals doesn’t work, so you need to hardcode that via each visual’s Format panel. I’m mentioning this because the primary appeal of this approach is to stack the HTML Content visual either below or on top of other visuals. We can achieve dynamic partial transparency within the HTML Content visual as it’s something you can control with CSS.
4. Further Resources: CSS Is Its Own Universe
I only scratched the surface with this proof of concept. I’ll revisit this entry in the future to detail some of the possibilities, and will add a sample PBIX at some point. In the meantime, here are some pointers for the community to explore, I’d love to hear what you come up with!
- Liveweave, Codepen et. al. – browser-based live editors that let you test your HTML/CSS before porting to Power BI.
- Gradienta and Gradient Editor: dramatic multicolor gradients like the one shown above. Of course you don’t have to use gradients, it’s just one technique.
- CSS country flags.
- CSS Icons.
- One of many CSS tutorials.
- Advanced CSS Tricks and Techniques
- How to Hijack Power BI Styles to Apply Your Own
Among these advanced techniques, CSS transitions – including on hover – do work, as well as CSS animations:
Power BI tends to feel a bit “flat” and could use more affordance. These techniques might be an acceptable workaround to highlight buttons, add halos to cards when they’re showing extreme or unexpected values, or otherwise provide visual cues whenever warranted.
I focused this entry on creating background textures in a single div, but you could push the envelope much further by generating dynamic HTML as well. Good luck if you fall in that rabbit hole!
I don’t always write about Power BI, but when I do, I tend to research topics fairly extensively. Check out the Power BI category for posts on third-party tools, object level security, dataflows and more.