This post covers the following sections from my init.


* Css and Scss Modes

Preamble

Emacs is old school. You're either new to it - which means you wouldn't be here unless it was your type of thing - or you know what you're looking for. In either case, search 'Emacs' in tags or search on this site. Then read the posts y date from oldest to newest.

In the last emacs post I covered lines 3626 - 3796. This post covers lines 3995 - 4098. The lines don't always match up because I take stuff out when I'm in the init, and the init is literal. The lines then cover also notes that are not tangled.

CSS

There's not a lot of syntax in css, you just need to know how to use it. In most coding environments, autocompletion backends play the primary role in css and scss coding, as they provide dropdowns with completion hints. In Emacs, you set that up with company or autocomplete covered earlier.

Oh, before I continue, here's a clip from the movie Wargames starring Mathew Broderick.

When coding css and scss, a lot of people use also snippets or emmet mode completion. I tend to write css and scss with eldoc mode on by default (eldoc shows css completion options in the minibuffer). In some cases, I will turn on company mode, and often I use shortcuts to cheatsheets for rapid review, especially when mixing flex and css grid aligment properties.

Anyway, here's sort and eldoc:



;css sort
(use-package com-css-sort
:commands (com-css-sort com-css-sort-attributes-block com-css-sort-attributes-document)
:config
(setq com-css-sort-sort-type 'alphabetic-sort)
);end com-css-sort
;css-eldoc
(use-package css-eldoc
:commands turn-on-css-eldoc
;add a hook if you want always to see the selector options in the minibuffer
:config
(add-hook 'css-mode-hook 'turn-on-css-eldoc)
(add-hook 'scss-mode-hook 'turn-on-css-eldoc)
);end css-eldoc

Notes

Sort arranges selected selectors, to clean up your code. Eldoc shows completion options in the minibuffer


Origami



(use-package origami
:commands (origami-toggle-node origami-mode)
:config
(add-to-list 'origami-parser-alist '(scss-markers   . ,(origami-markers-parser "/*/" "/*/")))
(add-hook 'scss-mode-hook
          (lambda () (setq-local origami-fold-style 'scss-markers)))
:bind
("C-c i" . origami-toggle-node)
);end origami mode
(add-hook 'css-mode-hook
            (lambda ()
(set (make-local-variable 'company-backends) '(company-capf company-css  company-dabbrev-code company-dabbrev company-etags company-yasnippet))))
(add-hook 'css-mode-hook 'emmet-mode)
;sass

Notes

In any file, unless you have minimap enabled on side bar, folding code blocks is a priority. Otherwise you end up searching the filing looking for landmarks. I prefer folding to minimap (though I do like org-sidebar). The following code uses origami-mode to enable folding css blocks. It would be better to just use org-babel and literally program your sass files...


Origami Mode



(use-package origami
:commands (origami-toggle-node origami-mode)
:config
(add-to-list 'origami-parser-alist '(scss-markers   . ,(origami-markers-parser "/*/" "/*/")))
(add-hook 'scss-mode-hook
          (lambda () (setq-local origami-fold-style 'scss-markers)))
:bind
("C-c i" . origami-toggle-node)
);end origami mode
(add-hook 'css-mode-hook
            (lambda ()
(set (make-local-variable 'company-backends) '(company-capf company-css  company-dabbrev-code company-dabbrev company-etags company-yasnippet))))
(add-hook 'css-mode-hook 'emmet-mode)

Sass-Mode (Scss-Mode)

Sass is scss without the brackets. I use scss. My scss mode is identical to my css mode, which is configured only with origami, company completion, yasnippets, and css-eldoc. Scss mode offers the option to use emacs as a wrapper for the command line so you can process your scss at the push of a buttton. I don't use the following code, but here it is. Instead, I use a package.json file in the working directory with node packages watching the sass files to compile them on change. Hugo comes with sass compilation baked in. For other sites (custom Wordpress theme/child-theme), autoprefixer, html-minifier, uglify-js, postcss-cli, and maybe purgecss would be enough.



(use-package scss-mode
;:after(web-mode css-mode scss-mode)
:commands (scss-mode scss-compile css-mode web-mode)
:mode ("\\.scss" . scss-mode)
:init
(defun company-scss-mode-hook ()
  (set (make-local-variable 'company-backends) '(company-capf company-css  company-dabbrev-code company-dabbrev company-etags company-yasnippet)))
:config
(require 'scss-mode)
(setq scss-sass-command dart-p)
;(setq exec-path (cons (expand-file-name "C:/ProgramData/chocolatey/bin/sass") exec-path))
;(setq exec-path (cons (expand-file-name "C:/tools/dart-sass/") exec-path))
(setq scss-compile-at-save 'nil)
;(autoload 'scss-mode "scss-mode")
;require company-css
(require 'company-css)
;hook
(require 'flymake-sass)
:hook
(scss-mode . (lambda ()
    (progn
(highlight-indent-guides-mode -1)
(emmet-mode 1)
(company-mode 1)
(company-scss-mode-hook)
(setq emmet-preview-default -1)
(flymake-sass-load)
)));end hook
);end scss-mode
;use scss-mode

So that's it for my css and scss configuration. Next, is the hyrda. But before that, here's another clip from Mathew Broderick's 1983 movie Wargames. 💾 Simulation code is cool, however, I can't for the life of me figure war logic. Every calculation grostly distorts the value of human suffering. 😄



So Here's the Hydra



;css-mode hydra
(defvar css-mode-title (with-octicon "globe" "Css Mode Control"))
;generate hydra
(pretty-hydra-define Css-Mode (:title css-mode-title :quit-key "q" :color blue )
("Mode"
(
    ("1" beginning-of-buffer "Go To Top Of Page")
    ("0" end-of-buffer "Go To Bottom Of Page")
    ("e" emmet-mode "Emmet Mode" :toggle t)
    ("S" scss-mode  "Scss Mode" :toggle t)
    ("M" sass-meister "Sass Meister Validator")
    ("e" emmet-mode "Emmet Mode" :toggle t )
    ("E" emmet-cheat-sheet "Emmet Cheat Sheet")
    ("b" bezier-curves "Animation Bezier Curves")
    ("g" origami-mode  "Origami Mode" :toggle t)

);end mode
"Action"
(

	("s"  com-css-sort-attributes-block "Alphabetic Sort Css In Block")
    ("D" com-css-sort-attributes-document "Alphabetic Sort Css Document")
    ("o" origami-toggle-node  "Toggle Origami Fold")
	("r" origami-recursively-toggle-node)
    ("p" origami-previous-fold)
    ("n" origami-next-fold)
    ("a" origami-open-all-nodes)
    ("c" origami-close-all-nodes)
;   ("I" highlight-indent-guides-mode  "Show Indent Guides" :toggle t )
);end action

"Other"
(
    ("i" yas-insert-snippet "Insert Snippet" )
	("t" company-try-hard "Cycle Completion Backends")
;     ( "V" code-validator "Code Validator")
    ("v"  Web-Mode/body "Web Mode Interface" :color blue)
    ("j" Javascripts/body "Javascript Interface" :color blue)
    ("w" Web-Development/body "Web Dev Interface" :color blue)
    ("h" hydra-helm/body "Return To Helm" :color blue )
    ("<SPC>" nil "Quit" :color blue)

);end other
);end hydra body
);end pretty-hydra-css
(bind-key "<C-m> i" 'Css-Mode/body)

Update: <2021-02-08> Added literal files for Scss

Css files get huge and complex. Sass (or Scss) enables file includes to better organize code, as well as other programming options, like nesting. I use nesting to mirror html structure, which is intuitive and fast. Then headers and folding are even more helpful.

Moreover, with 10 or so sass files (5 to overwrite the cascade), you end up jumping between files again.

With code folding you can combine those 5 files and whip through the document easily. It's essential. Only Origami doesn't come close to org-mode. Org is just so versatile. So here's what I've done to make it work.

Recycled a function to strip org-mode headings from documents before export. Written a function to export to .scss files. And configured a few org-export-to-ascii parameters to get org to export scss to an scss file. There's nothing brilliant about the elisp code, but what it does is gorgeous 😏



;first you set some margins to keep your code clean

(setq org-ascii-global-margin 0)
(setq org-ascii-inner-margin 0)
(setq org-ascii-indented-line-width 0)

;this one keeps your output from wrapping (which won't compile)
(setq org-ascii-text-width most-positive-fixnum)

;this comes from the org manual, it strips headings before export

(defun my-headline-removal (backend)
  "Remove all headlines in the current buffer.
BACKEND is the export back-end being used, as a symbol."
  (org-map-entries
   (lambda () (delete-region (point) (line-beginning-position 2)))))

; This one strips .org from your 'org-file.org', saves the name and adds '_org-file.scss'
; then it strips headings from your org file, exports to a buffer and writes that buffer to the new name

(defun export-org-to-scss ()
(interactive)
(let* (
(new-extension ".scss")
(new-file-name (concat (file-name-nondirectory (substring buffer-file-name 0 -4)) new-extension))
(sass-file-name (concat "_" new-file-name)))
(progn
(add-hook 'org-export-before-parsing-hook 'my-headline-removal)
(org-ascii-export-as-ascii)
(remove-hook 'org-export-before-parsing-hook 'my-headline-removal t)
(switch-to-buffer "*Org ASCII Export*")
(write-region (point-min) (point-max) sass-file-name)
(previous-buffer))))

I added 'export-org-to-scss' to the scss hydra. Now you can organize your scss files like org documents and easily compile them to your watched directory. Works great with Hugo's integrated server.


That’s all for now…