
Отзывчивые навигационные панели являются одними из хлеба и масла фронтенд-разработки. Обычной практикой является панель навигации на рабочем столе и боковая панель на мобильных устройствах. Вероятно, это очень легко реализовать с помощью ваших любимых фреймворков CSS. Тем не менее, это оказывается либо довольно сложным, либо совершенно сложным при использовании фреймворка semantic-UI-react (который, за исключением этой маленькой причуды, является удивительным фреймворком). Эта статья представляет собой демонстрацию того, как создать адаптивную панель навигации с помощью React, Semantic-UI-React и React-Response, поскольку на момент написания практически не было готовых решений.

Запись выше — это образец панели навигации, которую мы будем создавать на протяжении всей статьи.
В конце этой статьи вы узнаете, как:
- сделать отзывчивую панель навигации с помощью
semantic-UI-reactCSS framework - используйте пакет
react-responsive
Что такое Semantic-UI-реакция?
Semantic UI — один из многих популярных фреймворков CSS, которые якобы ускоряют создание веб-сайтов, предоставляя нам уже готовые компоненты CSS. Он гордится тем, что является семантическим, что в основном достигается за счет использования продуманных и осмысленных имен классов. Теперь, после использования таких фреймворков, как bootstrap и tailwind, я должен признать, что четкие, продуманные имена классов стали весьма ценными!
Фреймворк semantic-UI-react является расширением CSS-фреймворка semantic-UI, оптимизированным для работы с реакцией и использования системы поддержки реакции (так же, как у нас есть bootstrap и react-bootstrap). И это работает как шарм, пока вам не нужно создать отзывчивую панель навигации.
Что такое React-Responsive?
React-responsive — это пакет, который позволяет нам динамически вводить и удалять контент, отображаемый React в данный момент на экране, в зависимости от размера области просмотра. Используя этот пакет, мы можем имитировать медиа-запросы CSS-экрана непосредственно в коде реакции. Это мой любимый инструмент для адаптивного дизайна в React. Не стесняйтесь использовать любой альтернативный пакет, который может воспроизвести ту же функциональность.
Настраивать
Для начала:
- запустить приложение React (в этой демонстрации используется
vite-react) - очистите приложение, чтобы оно соответствовало файловой структуре на картинке ниже

- Установите пакеты semantic-UI-react, semantic-UI-CSS и пакеты, реагирующие на реакцию, с помощью NPM.
- Добавьте любое изображение логотипа по вашему выбору в общую папку
- Импортируйте
semantic.min.cssвmain.jsx. Этот импорт должен быть вышеindex.css, чтобы мы могли использоватьindex.cssдля перезаписи некоторых встроенных стилей семантической реакции пользовательского интерфейса, если это необходимо. - Добавьте следующие строки кода в указанные компоненты
/*index.css*/
body {
background-color: rgb(35, 35, 141)
}
//app.jsx
import Navbar from "./components/navbar"
function App() {
return (
<div className="App">
<Navbar />
</div>
)
}
export default App
//Main.jsx
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'
import 'semantic-ui-css/semantic.min.css'
import './index.css'
ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
<App />
</React.StrictMode>
)
Компонент NavbarLg
Мы будем использовать компонент меню для панели навигации на больших экранах. Для этого посетите semantic-UI-react docs и выберите предпочитаемый тип компонента меню. В этой демонстрации будет использоваться инвертированный тип меню.

- Документы написаны с использованием компонентов класса React, но это довольно простой код, поэтому я преобразую его в функциональный компонент.
- Мы также добавим ссылку для регистрации и входа в правый край панели навигации.
import { useState} from 'react'
import { Menu, Segment } from 'semantic-ui-react'
export default function NavbarLg() {
const [activeItem,setactiveItem]=useState("home")
const handleItemClick = (e, { name }) => setactiveItem(name)
return (
<Segment inverted attached size='mini'>
<Menu inverted secondary>
<Menu.Item
name='logo'
active={activeItem === 'logo'}
onClick={handleItemClick}
>
<img src="ghostblog.svg" alt="" />
</Menu.Item>
<Menu.Item
name='home'
active={activeItem === 'home'}
onClick={handleItemClick}
/>
<Menu.Item
name='messages'
active={activeItem === 'messages'}
onClick={handleItemClick}
/>
<Menu.Item
name='friends'
active={activeItem === 'friends'}
onClick={handleItemClick}
/>
<Menu.Item
name='login'
active={activeItem === 'login'}
onClick={handleItemClick}
position="right"
/>
<Menu.Item
name='sign_in'
active={activeItem === 'sign_in'}
onClick={handleItemClick}
/>
{/* section */}
</Menu>
</Segment>
)
}
//navbar.jsx
import NavbarLg from "./NavbarLg"
export default function Navbar() {
return (
<div>
<NavbarLg/>
</div>
)
}

Компонент NavbarMb
Переходя к мобильной панели навигации, мы будем использовать боковую панель semantic-UI-react (см. https://react.semantic-ui.com/modules/sidebar/), но внесем в нее некоторые серьезные изменения.

Проблема заключается в том, как семантический пользовательский интерфейс добавил оверлей, который вынуждает весь остальной контент на странице находиться в компоненте sidebar.pusher. Это неэффективно, учитывая, что мы не хотели бы вкладывать весь контент нашего приложения в этот компонент. Кроме того, элементы управления боковой панели нуждаются в доработке, так как значок гамбургера был бы гораздо предпочтительнее, чем галочка. Чтобы исправить все это, мы добавим три пользовательских компонента.
- Компонент тонированного наложения
- Значок гамбургера, чтобы открыть боковую панель
- Значок закрытия, чтобы закрыть боковую панель
Примечание: мы будем использовать встроенные значки семантического интерфейса.
Значок гамбургера будет переключаться в зависимости от состояния боковой панели, чтобы открыть или закрыть значок.
//NavbarMb.jsx
import { useState } from 'react'
import { Menu, Sidebar } from 'semantic-ui-react'
function Overlay() {
return (
<div style={{
backgroundColor: "rgba(0, 0, 0, 0.795)",
position: "fixed",
height: "110vh",
width: "100%",
}} />
)
}
function HamIcon() {
return (<i className="big bars icon inverted" />)
}
function CloseIcon() {
return (<i className="big close red icon" />)
}
function NavbarMb({renderLinks}) {
const [visible, setVisible] = useState(false)
const [icon, setIcon] = useState(HamIcon)
const [activeItem, setactiveItem] = useState("home")
const handleItemClick = (e, { name }) => setactiveItem(name)
const hideSidebar = () => {
setIcon(HamIcon)
setVisible(false)
}
const showSidebar = () => {
setIcon(CloseIcon)
setVisible(true)
}
const toggleSidebar = () => {
visible ? hideSidebar() : showSidebar()
}
return (
<>
{visible && <Overlay />}
<Menu inverted
size="tiny"
borderless
attached
>
<Menu.Item>
<img src="ghostblog.svg" width="35px" height="35px" alt="" />
</Menu.Item>
<Menu.Menu position='right'>
<Menu.Item onClick={toggleSidebar}>
{icon}
</Menu.Item>
</Menu.Menu>
</Menu>
<Sidebar as={Menu}
animation='overlay'
icon='labeled'
inverted
vertical
visible={visible}
width='thin'
>
<Menu.Item>
<img src="ghostblog.svg" width="35px" height="35px" style={{ margin: "0 auto" }} alt="" />
</Menu.Item>
<Menu.Item
name='home'
active={activeItem === 'home'}
onClick={handleItemClick}
/>
<Menu.Item
name='messages'
active={activeItem === 'messages'}
onClick={handleItemClick}
/>
<Menu.Item
name='friends'
active={activeItem === 'friends'}
onClick={handleItemClick}
/>
<Menu.Item
name='login'
active={activeItem === 'login'}
onClick={handleItemClick}
position="right"
/>
<Menu.Item
name='sign_in'
active={activeItem === 'sign_in'}
onClick={handleItemClick}
/>
</Sidebar>
</>
)
}
export default NavbarMb
//navbar.jsx
import NavbarMb from "./NavbarMb"
import NavbarLg from "./NavbarLg"
export default function Navbar() {
return (
<div>
{/*<NavbarLg/>*/}
<NavbarMb/>
</div>
)
}

Повтор сеанса с открытым исходным кодом
OpenReplay – это пакет для воспроизведения сеансов с открытым исходным кодом, который позволяет вам видеть, что пользователи делают в вашем веб-приложении, помогая вам быстрее устранять неполадки. OpenReplay размещается на собственном сервере для полного контроля над вашими данными.

Начните получать удовольствие от отладки — начните использовать OpenReplay бесплатно.
Делаем навигационную панель отзывчивой с помощью React-responsive
У нас есть навигационная панель для большого экрана и одна для мобильного экрана. Давайте поработаем с react-responsive, чтобы сделать панель навигации отзывчивой, переключаясь с navbar-large на navbar-mobile и наоборот в зависимости от размера экрана.
Мы сделаем это в компоненте навигационной панели, используя отзывчивый ответ.
- Импортируйте
NavbarLgиNavbarMbв компонентNavbar - Следуя отзывчивым документам, объявите несколько точек останова как переменные, используя хук
useMediaQuery. - Создайте объект размеров экрана из точек останова
- Отображение компонента
NavbarLgилиNavbarMbусловно в зависимости от того, превышает ли размер экрана точку останова или нет
Примечание. Этот пакет (реагирующий на реакцию) довольно прост в использовании, и документация очень ясно описывает, как его использовать.
//navbar.jsx
import { useMediaQuery } from 'react-responsive'
import NavbarMb from "./NavbarMb"
import NavbarLg from "./NavbarLg"
export default function Navbar() {
const none =useMediaQuery({ query: "(max-width:576px)" })
const sm = useMediaQuery({ query: "(min-width:576px)" })
const md = useMediaQuery({ query: "(min-width:768px)" })
const lg = useMediaQuery({ query: "(min-width:992px)" })
const xl = useMediaQuery({ query: "(min-width:1200px)" })
const xxl = useMediaQuery({ query: "(min-width:1400px)" })
const size = {none,sm,md,lg,xl,xxl}
return (
<div>
{size.sm ? <NavbarLg /> : <NavbarMb /> }
</div>
)
}

Вроде все закончили, но не совсем. Если вы посмотрите достаточно внимательно, вы заметите, что состояние не сохраняется после перехода с большой панели навигации на мобильную панель навигации. Это видно по выделенному nav-link, который снова меняется на home, когда мы переключаемся с большой панели навигации на мобильную панель навигации и наоборот.
Теперь представьте, что это многостраничное приложение React. Это, вероятно, приведет к путанице, поскольку, если кто-то на странице входа свернет свой экран, панель навигации вернется к выделению home, даже если приложение останется на странице входа.
Чтобы исправить это,
- мы поднимем состояние
nav-linksдо основного компонента Navbar и будем обрабатывать клики оттуда. - Затем
nav-linksможно передатьNavbarLgилиNavbarMbв качестве реквизита. Это сохранит состояние, посколькуnav-linksявляются частью компонентаNavbar, а компонентNavbarвсегда будет присутствовать в нашем пользовательском интерфейсе на больших и малых экранах.
//navbar.jsx
import { useState} from 'react'
import { useMediaQuery } from 'react-responsive'
import { Menu } from 'semantic-ui-react'
import NavbarMb from "./NavbarMb"
import NavbarLg from "./NavbarLg"
export default function Navbar() {
const [activeItem,setactiveItem]=useState("home")
const handleItemClick = (e, { name }) => setactiveItem(name)
const renderLinks=()=>{
return <><Menu.Item
name='logo'
active={activeItem === 'logo'}
onClick={handleItemClick}
>
<img src="ghostblog.svg" width="35px" height="35px" style={{ margin: "0 auto" }} alt="" />
</Menu.Item>
<Menu.Item
name='home'
active={activeItem === 'home'}
onClick={handleItemClick}
/>
<Menu.Item
name='messages'
active={activeItem === 'messages'}
onClick={handleItemClick}
/>
<Menu.Item
name='friends'
active={activeItem === 'friends'}
onClick={handleItemClick}
/>
<Menu.Item
name='login'
active={activeItem === 'login'}
onClick={handleItemClick}
position="right"
/>
<Menu.Item
name='sign_in'
active={activeItem === 'sign_in'}
onClick={handleItemClick}
/>
</>
}
const none =useMediaQuery({ query: "(max-width:576px)" })
const sm = useMediaQuery({ query: "(min-width:576px)" })
const md = useMediaQuery({ query: "(min-width:768px)" })
const lg = useMediaQuery({ query: "(min-width:992px)" })
const xl = useMediaQuery({ query: "(min-width:1200px)" })
const xxl = useMediaQuery({ query: "(min-width:1400px)" })
const size = {none,sm,md,lg,xl,xxl}
return (
<div>
{size.sm ? <NavbarLg renderLinks={renderLinks}/> : <NavbarMb renderLinks={renderLinks}/> }
</div>
)
}
//NavbarLg.jsx
import { Menu, Segment } from 'semantic-ui-react'
export default function NavbarLg({renderLinks}) {
return (
<Segment inverted attached size='mini'>
<Menu inverted secondary>
{renderLinks()}
</Menu>
</Segment>
)
}
//Navbar.Mb
import { useState } from 'react'
import { Menu, Sidebar } from 'semantic-ui-react'
function Overlay() {
return (
<div style={{
backgroundColor: "rgba(0, 0, 0, 0.795)",
position: "fixed",
height: "110vh",
width: "100%",
}} />
)
}
function HamIcon() {
return (<i className="big bars icon inverted" />)
}
function CloseIcon() {
return (<i className="big close red icon" />)
}
function NavbarMb({renderLinks}) {
const [visible, setVisible] = useState(false)
const [icon, setIcon] = useState(HamIcon)
const hideSidebar = () => {
setIcon(HamIcon)
setVisible(false)
}
const showSidebar = () => {
setIcon(CloseIcon)
setVisible(true)
}
const toggleSidebar = () => {
visible ? hideSidebar() : showSidebar()
}
return (
<>
{visible && <Overlay />}
<Menu inverted
size="tiny"
borderless
attached
>
<Menu.Item>
<img src="ghostblog.svg" width="35px" height="35px" alt="" />
</Menu.Item>
<Menu.Menu position='right'>
<Menu.Item onClick={toggleSidebar}>
{icon}
</Menu.Item>
</Menu.Menu>
</Menu>
<Sidebar as={Menu}
animation='overlay'
icon='labeled'
inverted
vertical
visible={visible}
width='thin'
>
{renderLinks()}
</Sidebar>
</>
)
}
export default NavbarMb

Краткое содержание
Эта демонстрация длинная, но если вы когда-нибудь столкнетесь с трудностями при работе с адаптивной панелью навигации с помощью Semantic-UI или Semantic-UI-react, она должна вам помочь.
Кроме того, благодаря тому, что компоненты реакции легко повторно использовать, компонент навигационной панели можно повторно использовать в нескольких проектах. С помощью стиля semantic-UI-react мы можем вносить соответствующие изменения и изменения в дизайн, чтобы он подходил для любого конкретного проекта.
Ресурсы

Первоначально опубликовано на https://blog.openreplay.com.