Normalize URLs with PostCSS
npx @tessl/cli install tessl/npm-postcss-normalize-url@7.0.00
# PostCSS Normalize URL
1
2
PostCSS Normalize URL is a PostCSS plugin that normalizes URLs within CSS stylesheets. It automatically optimizes URL formats for better compression and standardization by removing unnecessary port numbers, converting absolute URLs to more efficient formats, normalizing relative paths, and intelligently managing quotes around URLs.
3
4
## Package Information
5
6
- **Package Name**: postcss-normalize-url
7
- **Package Type**: npm
8
- **Language**: JavaScript
9
- **Installation**: `npm install postcss-normalize-url`
10
11
## Core Imports
12
13
```javascript
14
const postcssNormalizeUrl = require("postcss-normalize-url");
15
```
16
17
ES modules:
18
19
```javascript
20
import postcssNormalizeUrl from "postcss-normalize-url";
21
```
22
23
24
## Basic Usage
25
26
```javascript
27
const postcss = require("postcss");
28
const postcssNormalizeUrl = require("postcss-normalize-url");
29
30
// Use as PostCSS plugin
31
const result = await postcss([postcssNormalizeUrl()])
32
.process("h1 { background: url(\"http://site.com:80/image.jpg\") }", {
33
from: undefined
34
});
35
36
console.log(result.css);
37
// Output: h1 { background: url(http://site.com/image.jpg) }
38
```
39
40
41
## Capabilities
42
43
### PostCSS Plugin Creator
44
45
Creates a PostCSS plugin instance for URL normalization in CSS.
46
47
```javascript { .api }
48
/**
49
* Creates a PostCSS plugin that normalizes URLs in CSS
50
* @returns {Plugin} PostCSS plugin object with postcss property
51
*/
52
function postcssNormalizeUrl(): Plugin;
53
54
// Plugin properties
55
postcssNormalizeUrl.postcss = true;
56
```
57
58
The plugin processes CSS and performs the following normalizations:
59
60
- **Port Removal**: Removes default ports (`:80` for HTTP, `:443` for HTTPS)
61
- **Quote Optimization**: Removes unnecessary quotes around URLs, adds escaping when needed
62
- **Path Normalization**: Normalizes relative paths using Node.js path.normalize and resolves directory traversals (`../`)
63
- **Protocol Handling**: Processes absolute URLs and protocol-relative URLs
64
- **Whitespace Handling**: Removes unnecessary whitespace inside URL functions and strings
65
- **Multiline Support**: Joins multiline URL strings that use backslash continuation
66
- **Special URL Preservation**: Leaves data URLs and browser extension URLs unchanged
67
- **Fragment Preservation**: Maintains URL fragments (hash portions) in both relative and absolute URLs
68
69
### @namespace Rule Processing
70
71
Processes CSS @namespace rules and normalizes URLs within them.
72
73
```javascript { .api }
74
// Plugin automatically handles @namespace rules
75
// Input: @namespace url("http://example.com:80/ns");
76
// Output: @namespace url(http://example.com/ns);
77
```
78
79
The plugin specifically processes:
80
- **@namespace Rules**: Converts url() functions to strings and normalizes them
81
- **Function to String Conversion**: Transforms url() functions to quoted strings in namespace contexts
82
- **Quote Management**: Preserves or adds appropriate quotes as needed
83
84
## Types
85
86
```typescript { .api }
87
interface Plugin {
88
postcssPlugin: 'postcss-normalize-url';
89
OnceExit(css: Root): void;
90
}
91
92
// Plugin creator function with postcss property
93
interface PluginCreator {
94
(): Plugin;
95
postcss: true;
96
}
97
98
// PostCSS types (from postcss package)
99
interface Root {
100
walk(callback: (node: Node) => boolean | void): Root;
101
}
102
103
interface Node {
104
type: string;
105
}
106
107
interface Declaration extends Node {
108
type: 'decl';
109
value: string;
110
}
111
112
interface AtRule extends Node {
113
type: 'atrule';
114
name: string;
115
params: string;
116
}
117
```
118
119
## Error Handling
120
121
The plugin includes robust error handling:
122
123
- **Malformed URLs**: Invalid URLs are left unchanged rather than breaking the build
124
- **Data URL Parsing**: Invalid data URLs fall back to the original value
125
- **Path Normalization**: Errors in path processing don't interrupt CSS processing
126
- **Extension URLs**: Browser extension URLs (e.g., `chrome-extension://`) are preserved unchanged
127
128
## URL Processing Examples
129
130
### Default Port Removal
131
```css
132
/* Input */
133
h1 { background: url("http://site.com:80/image.jpg") }
134
135
/* Output */
136
h1 { background: url(http://site.com/image.jpg) }
137
```
138
139
### Quote Optimization
140
```css
141
/* Input */
142
h1 { background: url("simple-image.jpg") }
143
144
/* Output */
145
h1 { background: url(simple-image.jpg) }
146
```
147
148
### Special Character Escaping
149
```css
150
/* Input */
151
h1 { background: url("path with spaces.jpg") }
152
153
/* Output */
154
h1 { background: url("path with spaces.jpg") }
155
```
156
157
### Relative Path Normalization
158
```css
159
/* Input */
160
h1 { background: url("./images/../icons/icon.png") }
161
162
/* Output */
163
h1 { background: url(icons/icon.png) }
164
```
165
166
### Directory Traversal Resolution
167
```css
168
/* Input */
169
h1 { background: url("css/../font/t.eot") }
170
171
/* Output */
172
h1 { background: url(font/t.eot) }
173
```
174
175
### Whitespace Normalization
176
```css
177
/* Input */
178
h1 { background: url(" test.png ") }
179
180
/* Output */
181
h1 { background: url(test.png) }
182
```
183
184
### Multiline URL Handling
185
```css
186
/* Input */
187
h1 { background: url("some really long string \
188
spanning multiple lines") }
189
190
/* Output */
191
h1 { background: url("some really long string spanning multiple lines") }
192
```
193
194
### Fragment Preservation
195
```css
196
/* Input */
197
h1 { background: url("http://website.com/test.svg#icon") }
198
199
/* Output - fragment preserved */
200
h1 { background: url(http://website.com/test.svg#icon) }
201
```
202
203
### Data URL Preservation
204
```css
205
/* Input */
206
h1 { background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==") }
207
208
/* Output - preserved unchanged */
209
h1 { background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==") }
210
```