Open otaxhu opened 9 months ago
No need for SCSS: regular CSS supports nesting, I think templ may simply put it in the result without any transformation...
That is not 100% accurate if your target browser is an older one.
Sure! I did not say that all browsers support CSS nesting, but that nesting is now supported by regular CSS, therefore I think templ should allow us to do CSS nesting :-)
However, I think including SCSS into templ for nesting would be overkill...
After thinking again about this, I agree it does not fix the pseudo-class problem with non-nested CSS...
I believe this one still requires some decisions to be made, so have labelled as such so noone jumps to an implementation.
I'm thinking that we may be able to implement CSS variables directly in <style>
tags and provide an alternative to the existing style components that provides everything we might need.
The tdewolff parser is suitably open to extension such that I was able to put together a rough PoC of how JS variables could be introduced directly into script tags, without needing to have script components.
package main
import (
"fmt"
"io"
"log"
"strings"
"unicode"
"github.com/a-h/templ/parser/v2/goexpression"
"github.com/tdewolff/parse/v2"
"github.com/tdewolff/parse/v2/js"
)
func NewJSExpressionParser(content string) *JSExpressionParser {
input := parse.NewInputString(content)
return &JSExpressionParser{
Content: content,
Input: input,
Lexer: js.NewLexer(input),
BraceCount: 0,
GoExpressions: nil,
}
}
type JSExpressionParser struct {
Content string
Input *parse.Input
Lexer *js.Lexer
// BraceCount is the number of sequential braces we've just seen.
// If we see `{{` then we should start parsing Go code.
BraceCount int
GoExpressions []Range
}
type Range struct {
Index int
Content string
}
func (p *JSExpressionParser) Parse() (err error) {
for {
tt, _ := p.Lexer.Next()
switch tt {
case js.ErrorToken:
if p.Lexer.Err() != io.EOF {
return p.Lexer.Err()
}
return
case js.OpenBraceToken:
p.BraceCount++
if p.BraceCount == 2 {
expr := Range{
Index: p.Input.Offset(),
}
_, e, err := goexpression.Expression(p.Content[p.Input.Offset():])
if err != nil {
return fmt.Errorf("failed to parse Go: %w", err)
}
expr.Content = p.Content[expr.Index : expr.Index+e]
p.GoExpressions = append(p.GoExpressions, expr)
// Seek past the end of the Go expression we just parsed.
p.Input.Move(e + 1)
// Get rid of whitespace.
for {
r, l := p.Input.PeekRune(1)
if unicode.IsSpace(r) {
p.Input.Move(l)
continue
}
break
}
// Clear braces.
if err = take(p.Input, "}}"); err != nil {
return fmt.Errorf("unclosed Go expression: %v", err)
}
}
default:
p.BraceCount = 0
}
}
}
func take(input *parse.Input, expected string) error {
var actual strings.Builder
for i := 0; i < len(expected); i++ {
a, _ := input.PeekRune(i)
actual.WriteRune(a)
}
if expected != actual.String() {
return fmt.Errorf("expected %q, got %q", expected, actual.String())
}
input.Move(len(expected))
return nil
}
func main() {
content := `const x = {{ y }};`
p := NewJSExpressionParser(content)
err := p.Parse()
if err != nil {
log.Fatalf("failed to parse: %v", err)
}
fmt.Printf("%#+v", p.GoExpressions)
}
I think the same logic could be applied to CSS components, allowing the use of this sort of thing:
templ Page(bgColor string) {
<style type="text/css">
@media print {
body {
background-color: {{ bgColor }};
}
}
</style>
}
Some work would be required to think about if/how class names get scoped to their components, but the parser part, at least, looks like it's not hard to achieve.
Some work would be required to think about if/how class names get scoped to their components, but the parser part, at least, looks like it's not hard to achieve.
On the topic of how class name would be scoped, Vue does this by looking for a special scoped
property on the style tag.
<style scoped>
.myClass { }
</style>
https://vuejs.org/api/sfc-css-features.html#scoped-css
Another use cases that might be worth considering is when a project have seperate css files. It would be nice to be able to use embed
on those files and also then get access to the class name scoping feature.
what's the solution for this now?
what's the solution for this now?
I used a plain CSS file and added conditional logic to add specific class names.
<head>
<link rel="stylesheet" href="/assets/style.css"/>
</head>
First if all. Thank you for you work with templ. I love everything about it! (except for googling the name "templ") :)
I think CSS nesting and pseudo selectors would be fantastic to have in templ. And even other CSS features like media queries.
Here's my thoughts: When using templ + HTMX. Templ is giving a very nice way of "Componentify" each view. CSS scoping is usually handled by a big javascript framework + bundler + css preprocessor (like angular). In templ its just there out of the box. Right now it is limited by a number if CSS-features it doesn't support. It feels like its almost there. I have huge respect for if this is difficult to implement. But it would be truly awesome to have, I think.
we may be able to implement CSS variables directly in
I was experimenting with the library and found that there is no way to access the :hover pseudo-class nor any other pseudo-class or pseudo-element.
First I tried nested css, something like this:
Error message after trying generation of the code above:
I know that the css expression is like a class in a css file so I think that it could be the only one way to do it. Other way to do it could be with SCSS support or some other crazy thing