코드스피츠 css rendering 3회차 part2 (step 41) - style 클래스 생성

KHW·2021년 6월 15일
0

js-study

목록 보기
30/39

CSS 관련한 프레임워크를 만들어보기

목표

  • vendor prefix 해결 => 웹브라우저 마다 prefix를 붙여야 그나마 다른 방식의 지원을 막을 수 있는 것 같다.
  • css 동적 조정

vendor prefix란?

웹 브라우저 공급자가 새로운 실험적인 기능을 제공할 때 이전 버전의 웹 브라우저에 그 사실을 알려주기 위해 사용하는 접두사(prefix)를 의미

html과 다르게 css는 웹표준이 정해지지않아 브라우저에 따른 다른 방식이 지원된다.
따라서 css를 원활히 사용하기 위해 스타일 속성 앞에 prefix(접두사)를 붙여야한다.
(vendor는 노점상 이런뜻인데 브라우저를 고객에게처럼 prefix를 붙여서 해라 이런건가 개인적으로 혼자 생각)

프레임워크 구조

  • style (cssStyleDeclare)
  • rule (cssRule)
  • css (styleSheet)

style

const Style = ((_) => {
    const prop = new Map, prefix = 'webkt,moz,ms,chrome,o,khtml'.split(',');
  const NONE = Symbol();
  const BASE = document.body.style;		
  
  const getKey = (key) => {
    	if(prop.has(key)) return prop.get(key);
    	if(key in BASE) prop.set(key, key);
    	else if(!prefix.some(v =>{
  // prefix를 붙인 속성은 존재하는가?를 알아볼 차례
  // 메소드 some의 인수인 callback 함수 부분이다.
  // webkitBackground 이런식으로 속성명 첫글자가 대문자이므로 표준 key인 background의 앞에 vendor prefix를 붙이고 대문자로 바꾸고 나머지 뒤인 'ackground'를 붙여주는 작업이 필요하다.
  		const newKey = v + key[0].toUpperCase() + key.substr(1);
  		if(newKey in BASE){ // prefix붙인 속성이 body에 있다면,
    		prop.set(key, newKey); // border-radius 부르면 prefix를 붙인 진짜 이름을 캐시에 저장
    		key = newKey; // 리턴할 key는 더이상 원래 키가 아니라 newKey
    		return true; // 진짜 이름을 찾았으니 여기서 끊어 라는것. some을 더 돌지 않아도 된다고 끊어버리는 것이다.
  		} 	
          	else return false;
	})){
  // some의 결과가 false일 경우에만 여기에 들어온다.
 		 prop.set(key, NONE);
		 key = NONE;
	}
	return key; // 그냥 key가 리턴되든지, newKey가 리턴되든지, NONE이 리턴될 것임
  }; // end of getKey()
  
  
  return class {
    constructor(style) {
      this._style = style;
    } // 생성자에 style객체를 준다. 이 클래스는 style 객체를 안고 태어난다.
    // 키를 얻기(스타일 시트에 있는 background라는 값을 얻고싶다면?)
    get(key) {
      key = getKey(key); // 반드시 getKey에 보내서 진짜 이름을 얻어야 한다.
      if (key === NONE) return null; // 브라우저가 지원하지 않는 경우 부드럽게 null을 리턴하기 // Unsupported Property 문제 해결!
      return this._style[key]; // 이름이 있다면 진짜 이름으로 style객체에 해당 속성값을 가져오자
    }
    set(key, val) {
      key = getKey(key);
      // key가 NONE이 아니면
      if (key !== NONE) this._style[key] = val; // 값을 설정
      // NONE이면 스타일을 아예 건들지 않는다(Graceful Fail)
      return this; // set을 계속 호출하는 경우가 많아서 set을 쓸 수 있게 this를 리턴
    }
  };
})();

getKey : prop에 이미 key가 있다면 get을 통해 가져오고 document.body.style에서 해당 style과 관련한 것이 있다면 이를 set메소드로 적용시키고 둘다 아니라면 해당 prefix를 붙인 것이 존재하는가를 확인하여 있다면 set메소드를 작동시키고 true를 리턴하고 아니라면 false를 리턴한다. 그후 최종 key를 리턴

const BASE = document.body.style;을 통해 비교해야할 대상을 정하는데 모든 브라우저가 가지고 있는 document 의 body 의 style을 통해 vendor prefix가 있는지를 확인할 수 있다.

style class 적용해보기

<html>
  <head lang="en">
    <meta charset="UTF-8">     
    <style id='s'>
    .test{background:#ff0; width:200px;}
    </style>
<body>
    <div class="test">a</div>
</body>
<script>
const Style = (...)	//위의 내용 참조

const el = document.querySelector('#s');
const sheet = el.sheet;
const rules = sheet.cssRules;
const rule = rules[0];

const style = new Style(rule.style);
style.set('borderRadius','200px')
    .set('boxShadow','0 0 0 10px red')

</script>
</html>
  • 결과

    기존에 있었던 rule에서의 style부분을 적용한 style 변수를 만들어 내고 해당 변수에 set메소드를 적용시켜 모서리를 둥글게 하였고 10px의 빨간 테두리를 적용시켰다.

출처

코드복사
코드스피츠

210619 추가내용

  const prop = new Map, prefix = 'webkt,moz,ms,chrome,o,khtml'.split(',');
  const NONE = Symbol();
  const BASE = document.body.style;
  const getKey = (key) => {
    if(prop.has(key)) return prop.get(key);
    if(key in BASE) prop.set(key, key);
    else if(!prefix.some(v =>{
  const newKey = v + key[0].toUpperCase() + key.substr(1);
  if(newKey in BASE){ 
    prop.set(key, newKey); 
    key = newKey; 
    return true; 
  } else return false;
})){
  prop.set(key, NONE);
  key = NONE;
}
return key; 
};

 class Style {
    constructor(style) {
      this._style = style;
    } // 생성자에 style객체를 준다. 이 클래스는 style 객체를 안고 태어난다.
    // 키를 얻기(스타일 시트에 있는 background라는 값을 얻고싶다면?)
    get(key) {
      key = getKey(key); // 반드시 getKey에 보내서 진짜 이름을 얻어야 한다.
      if (key === NONE) return null; // 브라우저가 지원하지 않는 경우 부드럽게 null을 리턴하기 // Unsupported Property 문제 해결!
      return this._style[key]; // 이름이 있다면 진짜 이름으로 style객체에 해당 속성값을 가져오자
    }
    set(key, val) {
      key = getKey(key);
      // key가 NONE이 아니면
      if (key !== NONE) this._style[key] = val; // 값을 설정
      // NONE이면 스타일을 아예 건들지 않는다(Graceful Fail)
      return this; // set을 계속 호출하는 경우가 많아서 set을 쓸 수 있게 this를 리턴
    }
  };

위와같이도 가능은 한다.

profile
나의 하루를 가능한 기억하고 즐기고 후회하지말자

0개의 댓글