Как стилизовать переключатель Rebass
Используя Rebass/Forms в React, я не могу правильно изменить размер компонента Switch, используя стили. (Я также использую@emotion/styled
)
Я пробовал использовать size
атрибут, но это не дает желаемого эффекта простого изменения масштаба переключателя.
Я пробовал использовать sx
собственность и придать ей width
и height
, но это изменяет размер только элемента кнопки, а не внутреннего div, который является "скользящей точкой"
Я знаю, что могу написать некоторые стили, ориентированные на сам внутренний div, но я хотел бы найти способ задать ему высоту и ширину за один раз, и это применимо как к кнопке, так и к внутреннему div.
<Switch
sx={{ width: "30px", height: "15px" }}
/>
5 ответов
Невозможно сделать то, что вы хотите, "из коробки", потому что высота и ширина жестко заданы в исходном коде.
К счастью, внутренности rebass
очень хороши, поэтому можно создать свой собственный с небольшой копией пасты из исходного кода ребасса.
import React from "react";
import { Box } from "reflexbox";
export const ResizableSwitch = ({
checked,
height = 24,
width = 40,
...props
}) => (
<Box
as="button"
type="button"
role="switch"
tx="forms"
variant="switch"
aria-checked={checked}
{...props}
__css={{
appearance: "none",
m: 0,
p: 0,
width,
height,
color: "primary",
bg: "transparent",
border: "1px solid",
borderColor: "primary",
borderRadius: 9999,
"&[aria-checked=true]": {
bg: "primary"
},
":focus": {
outline: "none",
boxShadow: "0 0 0 2px"
}
}}
>
<Box
aria-hidden
style={{
transform: checked ? `translateX(${width - height}px)` : "translateX(0)"
}}
sx={{
mt: "-1px",
ml: "-1px",
width: height,
height,
borderRadius: 9999,
border: "1px solid",
borderColor: "primary",
bg: "background",
transitionProperty: "transform",
transitionTimingFunction: "ease-out",
transitionDuration: "0.1s",
variant: "forms.switch.thumb"
}}
/>
</Box>
);
https://codesandbox.io/s/styling-rebass-switch-r6tmx?file=/src/App.js
https://codesandbox.io/s/styling-rebass-switch-zto4z?file=/src/styles.css:37-1020
button.switch,
button.switch:hover,
button.switch:focus {
outline: none;
border: 1px solid grey;
box-shadow: none;
}
button.switch > div {
content: "";
width: 14px;
height: 14px;
background-color: #9fa2ab;
}
button.switch > div:after {
content: "";
position: absolute;
width: 20px;
height: 20px;
border-radius: 50%;
left: -2px;
top: -3px;
transition: left 0.3s ease, background-color 0.3s ease, box-shadow 0.1s ease,
transform 0.1s ease;
background-color: #5b5c60;
-webkit-box-shadow: 0px 3px 1px -2px rgba(0, 0, 0, 0.2),
0px 2px 2px 0px rgba(0, 0, 0, 0.14), 0px 1px 5px 0px rgba(0, 0, 0, 0.12);
box-shadow: 0px 3px 1px -2px rgba(0, 0, 0, 0.2),
0px 2px 2px 0px rgba(0, 0, 0, 0.14), 0px 1px 5px 0px rgba(0, 0, 0, 0.12);
}
button.switch[aria-checked="true"] {
background-color: #d0f35e;
}
button.switch[aria-checked="true"] > div:after {
background-color: #86af00;
}
button.switch[aria-checked="false"] {
background-color: #ffffff;
left: 18px;
}
Добавить переключатель класса
<Switch
className="switch"
sx={{ width: "30px", height: "15px" }}
checked={switched}
onClick={() => toggleSwitch()}
/>
Глядя на исходный код Switch, кажется, что никакие свойства не распространяются на внутреннюю<div>
... не могли бы вы открыть вопрос?
А пока вы можете установить свойства css для детей и / или на основе атрибутов:
.myswitch {
width: 30px !important;
height: 15px !important;
background: gray !important;
}
.myswitch[aria-checked="true"] {
background: red !important;
}
.myswitch div {
width: 15px;
height: 15px;
background: red;
}
тогда:
<Switch className="myswitch" />
К сожалению, нет. Я внимательно изучил сам пакет, и мне кажется, что нет фиксированного правила для компонентов, написанных в этом пакете. Некоторые компоненты получаютprops
и sx
. Но есть компоненты, вродеswitch
который размещает другой компонент в качестве дочерних, и ему не передается никакая опора.
Если вы посмотрите на реализацию switch
на этой странице здесь:
export const Switch = forwardRef(({
checked,
...props
}, ref) =>
<Box
ref={ref}
as='button'
type='button'
role='switch'
tx='forms'
variant='switch'
aria-checked={checked}
{...props}
__css={{
appearance: 'none',
m: 0,
p: 0,
width: 40,
height: 24,
color: 'primary',
bg: 'transparent',
border: '1px solid',
borderColor: 'primary',
borderRadius: 9999,
'&[aria-checked=true]': {
bg: 'primary',
},
':focus': {
outline: 'none',
boxShadow: '0 0 0 2px'
},
}}>
<Box
aria-hidden
style={{
transform: checked ? 'translateX(16px)' : 'translateX(0)',
}}
sx={{
mt: '-1px',
ml: '-1px',
width: 24,
height: 24,
borderRadius: 9999,
border: '1px solid',
borderColor: 'primary',
bg: 'background',
transitionProperty: 'transform',
transitionTimingFunction: 'ease-out',
transitionDuration: '0.1s',
variant: 'forms.switch.thumb',
}}
/>
</Box>
)
Есть 2 Box
компоненты (которые являются базовым компонентом пакета), один является дочерним по отношению к другому. ПервоеBox
это область переключателя, а ребенок Box
это круг / кнопка, которую вы ищете. Если вы посмотрите на этот компонент, вы увидите, что в него не передается внешняя переменная, поэтому ничего нельзя изменить - стиль уже написан.
Это компонент Button/Circle:
<Box
aria-hidden
style={{
transform: checked ? 'translateX(16px)' : 'translateX(0)',
}}
sx={{
mt: '-1px',
ml: '-1px',
width: 24,
height: 24,
borderRadius: 9999,
border: '1px solid',
borderColor: 'primary',
bg: 'background',
transitionProperty: 'transform',
transitionTimingFunction: 'ease-out',
transitionDuration: '0.1s',
variant: 'forms.switch.thumb',
}}
/>
Если вы все еще хотите использовать этот пакет, вы можете преодолеть это, перезаписав CSS, присвоив компоненту имя класса и применив стиль к его дочерним элементам.
Кроме того, вы можете открыть проблему или предложить исправление в репозитории пакетов на github.
Вы можете использовать масштаб преобразования CSS для масштабирования элемента и его дочерних элементов. Поскольку вы используете эмоции, вот что с этим связано.
CodeSandbox: https://codesandbox.io/s/styling-rebass-switch-5fqku?file=/src/App.js
import React, { useState } from "react";
import styled from "@emotion/styled";
import { Label, Checkbox, Switch } from "@rebass/forms";
const Title = styled.h1`
text-align: center;
`;
const FormLabel = styled(Label)`
align-items: center;
`;
const Control = styled.div`
width: 40px;
`;
const Toggle = styled(Switch)`
transform: scale(.7)
`;
export default function App() {
const [switched, setSwitched] = useState(false);
const toggleSwitch = () => {
setSwitched(!switched);
};
return (
<div className="App">
<Title>How to Style Rebass/Forms Switch</Title>
<FormLabel sx={{ padding: "10px" }}>
<Control>
<Checkbox size="16px" sx={{ marginLeft: "10px" }} />
</Control>
CheckBox
</FormLabel>
<FormLabel sx={{ padding: "10px" }}>
<Control>
<Toggle
checked={switched}
onClick={() => toggleSwitch()}
/>
</Control>
Switch
</FormLabel>
</div>
);
}