Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/AccentDesign/gcss
CSS written in Go
https://github.com/AccentDesign/gcss
css golang
Last synced: 12 days ago
JSON representation
CSS written in Go
- Host: GitHub
- URL: https://github.com/AccentDesign/gcss
- Owner: AccentDesign
- License: mit
- Created: 2024-04-24T15:18:56.000Z (7 months ago)
- Default Branch: main
- Last Pushed: 2024-05-19T14:21:35.000Z (6 months ago)
- Last Synced: 2024-05-19T14:35:23.072Z (6 months ago)
- Topics: css, golang
- Language: Go
- Homepage: https://accentdesign.github.io/gcss
- Size: 102 KB
- Stars: 2
- Watchers: 3
- Forks: 1
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
[![Test](https://github.com/AccentDesign/gcss/actions/workflows/go-test.yml/badge.svg)](https://github.com/AccentDesign/gcss/actions/workflows/go-test.yml)
[![Go Report Card](https://goreportcard.com/badge/github.com/AccentDesign/gcss)](https://goreportcard.com/report/github.com/AccentDesign/gcss)# gcss
CSS written in Pure Go.
## Motivation
This is really just a bit of fun and a way to write CSS in Go. I wanted to see if it was possible and what would it look like.
I wanted to find a way to easily control the CSS from the server side and not have to worry about pre-building the css to take variables and stuff.
I didnt want to use UI libraries that are written for JS frameworks and I didn't want to use preprocessors or linters that add more steps to the build process.Could I just use CSS? Yes of course and I will, but I wanted to see if I could write CSS in Go as this is what is compiling the rest of the project.
## Gopher
No it looks nothing like the Go gopher, but it's a gopher and I like it. It's the best I could get from the LM without giving up, [ideogram.ai (1400097641)](https://ideogram.ai/g/E-5MQp7QTPO4uyF9PvERzw/3).
## Next stepsThe next steps for this project are to add more features to the CSS package.
This includes adding support for more CSS properties when the need arises.
What I don't want to do is to add support for all CSS functionality as some things are better in CSS, but I do want to be able to create
a few UI components that are configurable using Go.## Installation
```bash
go get github.com/AccentDesign/gcss
```## Quickstart
There is a separate repo with the full example [here](https://github.com/AccentDesign/gcss-starter) which will evolve over time.
```bash
git clone https://github.com/AccentDesign/gcss-starter.git
```install the dependencies:
```bash
# for hot reloading
go install github.com/cosmtrek/air@latest
``````bash
go mod tidy
```run the server:
```bash
air
```## Usage
### Basic usage
`gcss` defines a `Style` type that can be used to hold the properties for a specific css selector, eg:
```go
style := gcss.Style{
Selector: "body",
Props: gcss.Props{
BackgroundColor: props.ColorRGBA(0, 0, 0, 128),
},
}
```The `CSS` function on the `Style` is used to write the style to a `io.Writer`:
```go
style.CSS(os.Stdout)
```which gives you:
```css
body{background-color:rgba(0,0,0,0.50);}
```That's all there is to it. But it's not very useful on it's own I hear you say.
### Multiple styles
Well you can then use that to define a `Styles` type that can be used to hold multiple `Style` types:
```go
type Styles []gcss.Stylefunc (s Styles) CSS(w io.Writer) error {
// handle your errors
for _, style := range s {
style.CSS(w)
}
return nil
}styles := Styles{
{
Selector: "body",
Props: gcss.Props{
BackgroundColor: props.ColorRGBA(0, 0, 0, 128),
},
},
{
Selector: "main",
Props: gcss.Props{
Padding: props.UnitRem(8.5),
},
},
}styles.CSS(os.Stdout)
```which gives you:
```css
/* formatted for visibility */
body{
background-color:rgba(0,0,0,0.50);
}
main{
padding:8.500rem;
}
```### Need a bit more? what about a dark and light theme? keep the last example in mind and read on.
Define a `Theme` type that can be used to hold attributes for a specific theme, eg:
```go
type Theme struct {
MediaQuery string
Background props.Color
}func (t *Theme) CSS(w io.Writer) error {
// handle your errors
fmt.Fprintf(w, "%s{", t.MediaQuery)
for _, style := range t.Styles() {
style.CSS(w)
}
fmt.Fprint(w, "}")
}// Styles returns the styles for the theme.
// Can be any number of styles you want and any number of functions
// you just need them in the CSS function to loop over.
func (t *Theme) Styles() Styles {
return Styles{
{
Selector: "body",
Props: gcss.Props{
BackgroundColor: t.Background,
},
},
}
}
```Then you can define a `Stylesheet` type that can be used to hold multiple `Theme` types:
```go
type Stylesheet struct {
Dark *Theme
Light *Theme
}func (s *Stylesheet) CSS(w io.Writer) error {
// handle your errors
s.Dark.CSS(w)
s.Light.CSS(w)
return nil
}
```Finally, you can use the `Stylesheet` type to write the css to a `io.Writer`:
```go
styles := Stylesheet{
Dark: &Theme{
MediaQuery: "@media (prefers-color-scheme: dark)",
Background: props.ColorRGBA(0, 0, 0, 255),
},
Light: &Theme{
MediaQuery: "@media (prefers-color-scheme: light)",
Background: props.ColorRGBA(255, 255, 255, 255),
},
}styles.CSS(os.Stdout)
```gives you:
```css
/* formatted for visibility */
@media (prefers-color-scheme: dark) {
body{
background-color:rgba(0,0,0,1.00);
}
}
@media (prefers-color-scheme: light) {
body{
background-color:rgba(255,255,255,1.00);
}
}
```Hopefully this will get you going. The rest is up to you.
* Maybe create a button function that takes a `props.Color` and returns a Style.
* Or add extra `Styles` to the `Stylesheet` to additionally include non themed styles.
* It's all about how you construct the `Stylesheet` and use the `gcss.Style` type.
* If I could have created a `Stylesheet` type that fits well any use case at all I would have, but there is a world of possibility, so I left it up to you.## The benefits
* Total control of the CSS from the server side.
* CSS doesn't have mixins, but you can create a function that returns a `Style` type and reuse it.
* Keeps the css free of variables.
* Keeps html free of classes like `bg-gray-50 text-black dark:bg-slate-800 dark:text-white` and eliminates the need to remember to add the dark variant.
* I recently saw a button component on an html page 10 times with over 1800 characters in the class attribute of each. This is not maintainable nor debuggable.
* Keeps the css clean and easy to debug with no overrides like the above.## Examples
For example usage see the [examples](./examples) directory that include:
* [Full example](./examples/full) - A full example including base, media and themed styles with a `sync.Mutex` for caching the css in a `http.HandleFunc`.
* [CSS resets](./examples/css-resets) - A simple example collection of css resets.
* [Templ integration](./examples/integration-templ) - An example of how to load styles from gcss with the [templ](https://templ.guide) package.
* [Media queries](./examples/media-queries) - An example of how to use media queries.
* [Template function](./examples/template-function) - An example of how to write css to the template directly via `template.FuncMap` and `template.CSS`.
* [Write to a file](./examples/to-file) - An example of how to write to a file.
* [Write to an HTTP handler](./examples/to-http-handler) - An example of how to write to an http handler.
* [Write to stdout](./examples/to-stdout) - An example of how to write to stdout.## Contributing
If you would like to contribute to this project, please open an issue or a pull request. We welcome all contributions and ideas.
## Mix it up with other CSS frameworks
You can mix `gcss` with other CSS frameworks like `tailwindcss` for example:
separate the css files into base and utils:
```css
/* base.css */
@tailwind base;
``````css
/* utils.css */
@tailwind utilities;
```Then add the `gcss` styles in between in your html:
```html
```
Try to keep the specificity of the `gcss` styles to 1 by using single classes this will ensure any `tailwindcss` utilities
will be able to overwrite your styles where required.