Tarz Bileşenleri: Modern Web için JS İçinde CSS Kitaplığı

Yayınlanan: 2022-03-11

CSS, "eski web" in içermesi beklenen belgeler için tasarlandı. Sass veya Less gibi önişlemcilerin ortaya çıkması, topluluğun CSS'nin sunduğundan daha fazlasına ihtiyacı olduğunu gösteriyor. Web uygulamalarının zamanla daha karmaşık hale gelmesiyle, CSS'nin sınırlamaları giderek daha görünür hale geldi ve hafifletilmesi zorlaştı.

Tarz bileşenleri , eksiksiz bir programlama dilinin (JavaScript) gücünden ve kodu bileşenler halinde yapılandırmaya yardımcı olmak için kapsam belirleme yeteneklerinden yararlanır. Bu, büyük projeler için CSS yazmanın ve sürdürmenin yaygın tuzaklarından kaçınmaya yardımcı olur. Bir geliştirici, herhangi bir yan etki riski olmadan bir bileşenin stilini tanımlayabilir.

Sorun ne?

CSS kullanmanın bir avantajı, stilin koddan tamamen ayrılmış olmasıdır. Bu, geliştiricilerin ve tasarımcıların birbirine müdahale etmeden paralel olarak çalışabileceği anlamına gelir.

Öte yandan, stilli bileşenler , stil ve mantığı güçlü bir şekilde birleştirme tuzağına düşmeyi kolaylaştırır. Max Stoiber bundan nasıl kaçınılacağını açıklıyor. Mantık ve sunumu ayırma fikri kesinlikle yeni olmasa da, React bileşenlerini geliştirirken kısayollar almak cazip gelebilir. Örneğin, tıklama eyleminin yanı sıra düğmenin stilini de işleyen bir doğrulama düğmesi için bir bileşen oluşturmak kolaydır. İki bileşene bölmek biraz daha fazla çaba gerektirir.

Kapsayıcı/Sunum Mimarisi

Bu oldukça basit bir ilkedir. Bileşenler ya işlerin nasıl göründüğünü tanımlar ya da verileri ve mantığı yönetir. Sunum bileşenlerinin çok önemli bir yönü, hiçbir zaman bağımlılıklarının olmamasıdır. Sahne alırlar ve buna göre DOM (veya çocukları) oluştururlar. Konteynerler ise veri mimarisini (durum, redux, flux vb.) bilirler ancak görüntülemeden asla sorumlu olmamalıdırlar. Dan Abramov'un makalesi, bu mimarinin çok iyi ve ayrıntılı bir açıklamasıdır.

SMACSS'yi hatırlamak

CSS için Ölçeklenebilir ve Modüler Mimari, CSS'yi düzenlemek için bir stil kılavuzu olmasına rağmen, temel kavram, çoğunlukla otomatik olarak stil bileşenleri tarafından takip edilen kavramdır. Buradaki fikir, CSS'yi beş kategoriye ayırmaktır:

  • Baz tüm genel kuralları içerir.
  • Layout'un amacı, içeriğin çeşitli bölümlerinin (üstbilgi, altbilgi, kenar çubuğu, içerik, örneğin) yanı sıra yapısal özellikleri tanımlamaktır.
  • Modül , kullanıcı arayüzünün çeşitli mantıksal blokları için alt kategoriler içerir.
  • Durum , öğelerin durumlarını belirtmek için değiştirici sınıfları tanımlar, örneğin hatalı alan, devre dışı bırakılmış düğme.
  • Tema , değiştirilebilen veya kullanıcı tercihine bağlı olabilen renk, yazı tipi ve diğer kozmetik özellikleri içerir.

Tarz bileşenlerini kullanırken bu ayrımı korumak kolaydır. Projeler genellikle bir tür CSS normalleştirme veya sıfırlama içerir. Bu genellikle Temel kategorisine girer. Ayrıca genel yazı tipi boyutlandırmayı, satır boyutlandırmayı vb. tanımlayabilirsiniz. Bu, normal CSS (veya Sass/Less) veya styled-components tarafından sağlanan injectGlobal işlevi aracılığıyla yapılabilir.

Mizanpaj kuralları için, bir UI çerçevesi kullanıyorsanız, muhtemelen kap sınıfları veya bir ızgara sistemi tanımlayacaktır. Yazdığınız layout bileşenlerinde bu sınıfları kendi kurallarınız ile birlikte rahatlıkla kullanabilirsiniz.

Modül , stiller harici dosyalarda tarif edilmek yerine doğrudan bileşenlere eklendiğinden, stilli bileşenlerin mimarisi tarafından otomatik olarak takip edilir. Temel olarak, yazdığınız her stil bileşeni kendi modülü olacaktır. Yan etkiler konusunda endişelenmeden stil kodunuzu yazabilirsiniz.

Durum , bileşenleriniz içinde değişken kurallar olarak tanımladığınız kurallar olacaktır. CSS niteliklerinizin değerlerini enterpolasyon yapmak için bir fonksiyon tanımlamanız yeterlidir. Bir UI çerçevesi kullanıyorsanız, bileşenlerinize eklemek için faydalı sınıflarınız da olabilir. Muhtemelen CSS sözde seçici kurallarınız da olacaktır (vurgulu, odak vb.)

Tema , bileşenleriniz içinde basitçe enterpolasyon yapılabilir. Temanızı, uygulamanız boyunca kullanılacak bir dizi değişken olarak tanımlamak iyi bir fikirdir. Hatta kontrastları ve vurguları işlemek için renkleri programlı olarak (bir kitaplık kullanarak veya manuel olarak) türetebilirsiniz. Bir programlama dilinin tüm gücüne sahip olduğunuzu unutmayın!

Bir Çözüm İçin Onları Bir Araya Getirin

Daha kolay bir navigasyon deneyimi için onları bir arada tutmak önemlidir; Bunları türe göre (sunuşa karşı mantık) değil, işlevselliğe göre düzenlemek istiyoruz.

Böylece, tüm genel bileşenler (düğmeler ve benzeri) için bir klasörümüz olacak. Diğerleri projeye ve işlevlerine göre düzenlenmelidir. Örneğin kullanıcı yönetimi özelliklerimiz varsa o özelliğe özel tüm bileşenleri gruplamalıyız.

Tarz bileşenlerinin kapsayıcı/sunu mimarisini bir SMACSS yaklaşımına uygulamak için fazladan bir bileşen türüne ihtiyacımız var: yapısal. Üç çeşit bileşenle sonuçlanıyoruz; tarz, yapısal ve kapsayıcı. Tarz bileşenleri bir etiketi (veya bileşeni) süslediğinden, DOM'yi yapılandırmak için bu üçüncü tür bileşene ihtiyacımız var. Bazı durumlarda, bir kapsayıcı bileşeninin alt bileşenlerin yapısını işlemesine izin vermek mümkün olabilir, ancak DOM yapısı karmaşık hale geldiğinde ve görsel amaçlar için gerekli olduğunda, bunları ayırmak en iyisidir. İyi bir örnek, DOM'nin tipik olarak oldukça ayrıntılı hale geldiği bir tablodur.

Örnek Proje

Bu ilkeleri göstermek için tarifleri görüntüleyen küçük bir uygulama oluşturalım. Bir Tarifler bileşeni oluşturmaya başlayabiliriz. Ana bileşen bir denetleyici olacaktır. Durumu idare edecek - bu durumda, tariflerin listesi. Ayrıca verileri almak için bir API işlevi çağıracaktır.

 class Recipes extends Component{ constructor (props) { super(props); this.state = { recipes: [] }; } componentDidMount () { this.loadData() } loadData () { getRecipes().then(recipes => { this.setState({recipes}) }) } render() { let {recipes} = this.state return ( <RecipesContainer recipes={recipes} /> ) } }

Tariflerin listesini oluşturacaktır, ancak nasıl yapılacağını bilmesine gerek yoktur (ve olmamalıdır). Böylece tariflerin listesini alan ve DOM çıktısı veren başka bir bileşen oluşturuyoruz:

 class RecipesContainer extends Component{ render() { let {recipes} = this.props return ( <TilesContainer> {recipes.map(recipe => (<Recipe key={recipe.id} {...recipe}/>))} </TilesContainer> ) } }

Burada aslında bir kiremit ızgarası yapmak istiyoruz. Gerçek döşeme düzenini genel bir bileşen yapmak iyi bir fikir olabilir. Bunu çıkarırsak, şuna benzeyen yeni bir bileşen elde ederiz:

 class TilesContainer extends Component { render () { let {children} = this.props return ( <Tiles> { React.Children.map(children, (child, i) => ( <Tile key={i}> {child} </Tile> )) } </Tiles> ) } }

TilesStyles.js:

 export const Tiles = styled.div` padding: 20px 10px; display: flex; flex-direction: row; flex-wrap: wrap; ` export const Tile = styled.div` flex: 1 1 auto; ... display: flex; & > div { flex: 1 0 auto; } `

Bu bileşenin tamamen tanıtım amaçlı olduğuna dikkat edin. Tarzını tanımlar ve aldığı çocukları, karoların nasıl göründüğünü tanımlayan başka bir tarz DOM öğesinin içine sarar. Genel sunum bileşenlerinizin mimari olarak nasıl görüneceğine dair güzel bir örnek.

Ardından, bir tarifin neye benzediğini tanımlamamız gerekiyor. Nispeten karmaşık DOM'yi tanımlamak ve gerektiğinde stili tanımlamak için bir kapsayıcı bileşenine ihtiyacımız var. Bununla bitiriyoruz:

 class RecipeContainer extends Component { onChangeServings (e) { let {changeServings} = this.props changeServings(e.target.value) } render () { let {title, ingredients, instructions, time, servings} = this.props return ( <Recipe> <Title>{title}</Title> <div>{time}</div> <div>Serving <input type="number" min="1" max="1000" value={servings} onChange={this.onChangeServings.bind(this)}/> </div> <Ingredients> {ingredients.map((ingredient, i) => ( <Ingredient key={i} servings={servings}> <span className="name">{ingredient.name}</span> <span className="quantity">{ingredient.quantity * servings} {ingredient.unit}</span> </Ingredient> ))} </Ingredients> <div> {instructions.map((instruction, i) => (<p key={i}>{instruction}</p>))} </div> </Recipe> ) } }

Burada kapsayıcının bazı DOM üretimi yaptığına dikkat edin, ancak içerdiği tek mantık bu. İç içe stiller tanımlayabileceğinizi unutmayın, böylece stil gerektiren her etiket için stil öğesi oluşturmanız gerekmez. Burada içerik maddesinin adı ve miktarı için yaptığımız şey budur. Tabii ki, onu daha da bölebilir ve bir bileşen için yeni bir bileşen oluşturabiliriz. Parçalılığı belirlemek - projenin karmaşıklığına bağlı olarak - size kalmış. Bu durumda, bu sadece RecipeStyles dosyasındaki geri kalanıyla birlikte tanımlanan stilize edilmiş bir bileşendir:

 export const Recipe = styled.div` background-color: ${theme('colors.background-highlight')}; `; export const Title = styled.div` font-weight: bold; ` export const Ingredients = styled.ul` margin: 5px 0; ` export const Ingredient = styled.li` & .name { ... } & .quantity { ... } `

Bu alıştırmanın amacı için ThemeProvider'ı kullandım. Temayı, stilize edilmiş bileşenlerin aksesuarlarına enjekte eder. Bunu basitçe color: ${props => props.theme.core_color} , temadaki eksik niteliklerden korunmak için sadece küçük bir sarmalayıcı kullanıyorum:

 const theme = (key) => (prop) => _.get(prop.theme, key) || console.warn('missing key', key)

Ayrıca bir modülde kendi sabitlerinizi tanımlayabilir ve bunun yerine bunları kullanabilirsiniz. Örneğin: color: ${styleConstants.core_color}

Artıları

Tarz bileşenlerini kullanmanın bir avantajı, onu istediğiniz kadar az kullanabilmenizdir. En sevdiğiniz UI çerçevesini kullanabilir ve üstüne stil bileşenleri ekleyebilirsiniz. Bu aynı zamanda mevcut bir proje bileşenini bileşene göre kolayca taşıyabileceğiniz anlamına gelir. Düzenin çoğuna standart CSS ile stil vermeyi seçebilir ve yeniden kullanılabilir bileşenler için yalnızca stilli bileşenleri kullanabilirsiniz.

Eksileri

Tasarımcılar/stil entegratörleri, değişkenleri işlemek ve bunları Sass/Less yerine kullanmak için çok temel JavaScript'i öğrenmelidir.

Ayrıca proje yapısında gezinmeyi de öğrenmeleri gerekecek, ancak bu bileşenin klasöründeki bir bileşenin stillerini bulmanın, değiştirmeniz gereken kuralı içeren doğru CSS/Sass/Less dosyasını bulmaktan daha kolay olduğunu iddia ediyorum.

Sözdizimi vurgulama, linting, vb. istiyorlarsa araçlarını da biraz değiştirmeleri gerekecek. Bu Atom eklentisi ve bu babel eklentisi ile başlamak için iyi bir yer.