Визуальные компоненты Nivo строятся вокруг централизованной системы
темы, которая управляет всеми аспектами оформления графиков: цветами,
типографикой, сетками, осями, подсказками и элементами легенды. Вместо
разрозненной стилизации через CSS или inline-стили используется единый
объект темы, который распространяется через React Context с помощью
ThemeProvider.
Основная идея заключается в том, что визуальная консистентность графиков достигается не локальными настройками каждого элемента, а глобальным описанием стиля, которое переиспользуется всеми компонентами библиотеки.
В основе механизма лежит провайдер контекста:
import { ThemeProvider } from '@nivo/core'
ThemeProvider передаёт объект темы всем дочерним
компонентам графика без необходимости прокидывать props на каждом
уровне.
Пример базового использования:
import { ThemeProvider } from '@nivo/core'
import { ResponsiveBar } from '@nivo/bar'
const theme = {
background: '#1f2933',
textColor: '#ffffff'
}
const App = () => (
<ThemeProvider theme={theme}>
<div style={{ height: 400 }}>
<ResponsiveBar
data={data}
keys={['value']}
indexBy="label"
/>
</div>
</ThemeProvider>
)
Все компоненты внутри ThemeProvider получают доступ к
theme автоматически.
Объект темы Nivo имеет иерархическую структуру. Он включает не только базовые цвета, но и отдельные блоки для каждой части графика.
const theme = {
background: '#0f172a',
textColor: '#e2e8f0',
fontSize: 11,
axis: {},
grid: {},
legends: {},
tooltip: {},
}
Каждый блок отвечает за отдельную визуальную область.
Оси являются одним из наиболее настраиваемых элементов. Они включают стили линий, текста и тиков.
axis: {
domain: {
line: {
stroke: '#94a3b8',
strokeWidth: 1
}
},
ticks: {
line: {
stroke: '#94a3b8',
strokeWidth: 1
},
text: {
fill: '#e2e8f0',
fontSize: 12
}
},
legend: {
text: {
fill: '#f8fafc',
fontSize: 14,
fontWeight: 600
}
}
}
domain.line управляет базовой линией осиticks.line влияет на засечкиticks.text определяет подписи значенийlegend.text отвечает за подписи осейСетка часто используется для улучшения читаемости данных. В теме она настраивается отдельно:
grid: {
line: {
stroke: '#334155',
strokeWidth: 1
}
}
Сетка применяется как к вертикальным, так и к горизонтальным линиям в зависимости от типа графика.
Легенды управляют отображением категорий данных.
legends: {
text: {
fill: '#e2e8f0',
fontSize: 12
}
}
Дополнительно легенды могут учитывать:
Однако базовый уровень стилизации всегда идёт через
theme.legends.
Tooltip является динамическим элементом, который также подчиняется теме:
tooltip: {
container: {
background: '#111827',
color: '#f9fafb',
fontSize: 12,
borderRadius: 6,
padding: '8px 12px'
}
}
В отличие от статических элементов, tooltip часто комбинируется с пользовательскими компонентами, но даже в этом случае тема задаёт базовые стили контейнера.
Одним из ключевых механизмов является глубокое слияние объектов темы. При передаче частичной темы происходит merge с дефолтной конфигурацией Nivo.
Пример:
const customTheme = {
textColor: '#ffffff'
}
Все остальные параметры будут взяты из стандартной темы библиотеки.
Это позволяет изменять только необходимые части оформления без необходимости копировать весь объект.
Часто ThemeProvider применяется глобально:
import { ThemeProvider } from '@nivo/core'
const theme = {
background: '#0b1220',
textColor: '#cbd5e1',
grid: {
line: {
stroke: '#1f2937'
}
}
}
const Root = () => (
<ThemeProvider theme={theme}>
<Dashboard />
</ThemeProvider>
)
В такой конфигурации все графики наследуют единый визуальный стиль.
Несмотря на глобальный провайдер, каждый график может переопределять тему локально:
<ResponsiveLine
data={data}
theme={{
axis: {
ticks: {
text: {
fontSize: 10
}
}
}
}}
/>
Приоритет обычно выглядит следующим образом:
theme в компонентеВ сложных интерфейсах часто используется комбинированный подход:
const baseTheme = {
textColor: '#e5e7eb'
}
const darkOverrides = {
background: '#0f172a',
grid: {
line: {
stroke: '#1e293b'
}
}
}
const theme = {
...baseTheme,
...darkOverrides
}
Однако такой поверхностный merge не заменяет глубокое объединение, которое делает сама библиотека.
В TypeScript-окружении тема Nivo может быть типизирована, что снижает риск ошибок при кастомизации:
import { Theme } from '@nivo/core'
const theme: Theme = {
background: '#000',
textColor: '#fff'
}
Это позволяет выявлять несоответствия структуры ещё на этапе разработки.
Тема не влияет напрямую на вычисления данных, но может косвенно затрагивать производительность через:
При изменении объекта темы происходит повторный рендер графика, так как React воспринимает новую ссылку на объект как изменение состояния.
Частый сценарий — переключение между светлой и тёмной темой:
const theme = isDark
? darkTheme
: lightTheme
<ThemeProvider theme={theme}>
<ResponsiveBar data={data} />
</ThemeProvider>
Важно, что смена темы должна быть детерминированной, иначе возможны лишние перерендеры.
Помимо стандартных секций, тема может влиять на:
Пример расширенной кастомизации:
const theme = {
crosshair: {
line: {
stroke: '#64748b',
strokeWidth: 1
}
},
annotations: {
text: {
fill: '#facc15'
}
}
}
В реальных проектах тема Nivo часто синхронизируется с дизайн-токенами:
Пример интеграции с CSS variables:
const theme = {
textColor: getComputedStyle(document.documentElement)
.getPropertyValue('--text-primary')
}
Несмотря на гибкость, система имеет ряд ограничений:
Тем не менее, основная визуальная структура графиков контролируется именно через ThemeProvider, что обеспечивает предсказуемость и единообразие интерфейса.