Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

css: Cannot pass easily an url to background-image property in a css expression #261

Closed
otaxhu opened this issue Oct 30, 2023 · 7 comments
Closed
Labels
css enhancement New feature or request NeedsFix Needs implementing

Comments

@otaxhu
Copy link

otaxhu commented Oct 30, 2023

I have this problem where I can't easily pass a url to a css property that accepts the css function "url()"

The common sense tell me that the templ.URL() function works in this case but it doesn't. As an example I have this templ code:

package main

css myCss() {
    background-image: { templ.URL("/url/to/image.png") };
}

templ someTemplate() {
    <div class={ myCss() }>Some content with a background image</div>
}

main.go file:

package main

import (
    "context"
    "os"
)

func main() {
    someTemplate().Render(context.Background(), os.Stdout)
}

The generated code executed in os.Stdout and formatted looks like this:

<style type="text/css">
    .myCss_a54a {
        background-image: zTemplUnsafeCSSPropertyValue;
    }
</style>
<div class="myCss_a54a">Some content with a background image</div>

So it says that the url is a css unsafe value...

My solution was to preppend url(\" and append \") string literals, something like this:

css myCss() {
    background-image: { "url(\"" + templ.URL("/url/to/image.png") + "\")" };
}

And this works perfectly fine, but as you can see is verbosely obscene.

So i want to make a request of a function called something like templ.CSSURL() that behaves just exactly like the url() css vanilla function and also with url sanitization or something like that

@otaxhu otaxhu changed the title Cannot pass easily an url to background-image property in a css function (css expression): Cannot pass easily an url to background-image property in a css function Oct 30, 2023
@otaxhu otaxhu changed the title (css expression): Cannot pass easily an url to background-image property in a css function (css expression): Cannot pass easily an url to background-image property in a css expression Oct 30, 2023
@a-h
Copy link
Owner

a-h commented Nov 2, 2023

Thanks for raising this.

I think that what we need here is specific behaviour for the background-image CSS property.

As per https://github.com/google/safehtml/blob/be23134998433fcf0135dda53593fc8f8bf4df7c/style.go#L170 background-image is the only property that goes through URL sanitization.

I think that the generator could be updated so that if the CSS property is background-image, then it checks whether it's receiving a string in which case, the sanitization is applied and the expectation is that it's a string containing url('value'), or templ.URL, in which case, it's wrapped with url('value').

Thoughts on that?

@joerdav joerdav changed the title (css expression): Cannot pass easily an url to background-image property in a css expression css: Cannot pass easily an url to background-image property in a css expression Jan 30, 2024
@joerdav joerdav added enhancement New feature or request NeedsFix Needs implementing css labels Jan 30, 2024
@Oudwins
Copy link
Contributor

Oudwins commented Mar 15, 2024

What is the status on this? Currently I cannot even get the code to compile with the example otaxhu said was working.....

@koddr
Copy link

koddr commented Mar 18, 2024

The same problem.

Even after upgrading to v0.2.639: #578 (comment)

Hope @a-h check this 👍

@Oudwins
Copy link
Contributor

Oudwins commented Mar 19, 2024

@koddr what I did is just use a regular IMG tag as a bg image with the object fit property. See if that works for you.

@koddr
Copy link

koddr commented Mar 19, 2024

@Oudwins I didn't really understand what you mean, give me an example, please.

My tricky solution (I use Tailwind CSS classes):

css bgImage(u string) {
	background-image: { u };
}

templ Page(pictureUrl string) {
	<div class={ "h-48 bg-cover bg-center", bgImage(fmt.Sprintf("url(%s)", pictureUrl)) }>
		// ...
	</div>
}

Very cumbersome and absolutely terrible, yes.

On the other hand, we could implement this through the style={ ... } attribute, but Templ does not allow dynamic properties to be done with this attribute:

templ Page(pictureUrl string) {
	<div
		class="h-48 bg-cover bg-center"
		style={ fmt.Sprintf("background-image: url(%s)", pictureUrl) }
	></div>
}

Error in VS Code:

<div>: invalid style attribute: style attributes cannot be a templ expression: line 28, col 2

Error after templ generate:

(✗) Error generating code [ file=/Users/user/project/page.templ error=/Users/user/project/page.templ parsing error: <div>: invalid style attribute: style attributes cannot be a templ expression: line 28, col 2 ]
(✗) Event handler failed [ error=failed to generate code for "/Users/user/project/page.templ": /Users/user/project/page.templ parsing error: <div>: invalid style attribute: style attributes cannot be a templ expression: line 28, col 2 ]
(✗) Error [ error=failed to generate code for "/Users/user/project/page.templ": /Users/user/project/page.templ parsing error: <div>: invalid style attribute: style attributes cannot be a templ expression: line 28, col 2 ]
(✗) Command failed: generation completed with 1 errors

Therefore, I was really waiting for @a-h to release v0.2.639 that would work correctly with CSS elements and would not need to write such complex and difficult-to-read code in templates… but bug is still here, unfortunately 🥲

@a-h
Copy link
Owner

a-h commented Mar 19, 2024

Please refer to this example. I think the docs need to be updated, would take a PR for that.

package main

import "os"

templ page() {
	<!DOCTYPE html>
	<html>
		<head>
			<title>Background image</title>
		</head>
		<body>
			<div>
				@profile("image1.png")
			</div>
			<div>
				@profile("image2.png")
			</div>
		</body>
	</html>
}

templ profile(image string) {
	<div class={ profileCSS(image) }>
		Profile
	</div>
}

func bgImage(trustedURL string) templ.SafeCSSProperty {
	return templ.SafeCSSProperty("url(" + trustedURL + ")")
}

css profileCSS(image string) {
	background-image: { bgImage(image) };
}

func main() {
	page().Render(context.Background(), os.Stdout)
}

The output is:

<title>
 Background image
</title>
<div>
 <style type="text/css">
  .profileCSS_a59d{background-image:url(image1.png);}
 </style>
 <div class="profileCSS_a59d">
  Profile
 </div>
</div>
<div>
 <style type="text/css">
  .profileCSS_1fcd{background-image:url(image2.png);}
 </style>
 <div class="profileCSS_1fcd">
  Profile
 </div>
</div>

Also, thinking about the next version of templ, supporting this, where the CSS would automatically output url(%s) as per @otaxhu's suggestion.

css profileCSSNext(image string) {
	background-image: { templ.URL(image) };
}

@joerdav
Copy link
Collaborator

joerdav commented May 31, 2024

This is now documented: https://templ.guide/syntax-and-usage/css-style-management#css-sanitization

@joerdav joerdav closed this as completed May 31, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
css enhancement New feature or request NeedsFix Needs implementing
Projects
None yet
Development

No branches or pull requests

5 participants